home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / win / tkWinWm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  113.2 KB  |  4,118 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkWinWm.c --
  3.  *
  4.  *    This module takes care of the interactions between a Tk-based
  5.  *    application and the window manager.  Among other things, it
  6.  *    implements the "wm" command and passes geometry information
  7.  *    to the window manager.
  8.  *
  9.  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
  10.  *
  11.  * See the file "license.terms" for information on usage and redistribution
  12.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  13.  *
  14.  * SCCS: @(#) tkWinWm.c 1.64 97/08/12 14:08:58
  15.  */
  16.  
  17. #include "tkWinInt.h"
  18.  
  19. /*
  20.  * A data structure of the following type holds information for
  21.  * each window manager protocol (such as WM_DELETE_WINDOW) for
  22.  * which a handler (i.e. a Tcl command) has been defined for a
  23.  * particular top-level window.
  24.  */
  25.  
  26. typedef struct ProtocolHandler {
  27.     Atom protocol;        /* Identifies the protocol. */
  28.     struct ProtocolHandler *nextPtr;
  29.                 /* Next in list of protocol handlers for
  30.                  * the same top-level window, or NULL for
  31.                  * end of list. */
  32.     Tcl_Interp *interp;        /* Interpreter in which to invoke command. */
  33.     char command[4];        /* Tcl command to invoke when a client
  34.                  * message for this protocol arrives. 
  35.                  * The actual size of the structure varies
  36.                  * to accommodate the needs of the actual
  37.                  * command. THIS MUST BE THE LAST FIELD OF
  38.                  * THE STRUCTURE. */
  39. } ProtocolHandler;
  40.  
  41. #define HANDLER_SIZE(cmdLength) \
  42.     ((unsigned) (sizeof(ProtocolHandler) - 3 + cmdLength))
  43.  
  44. /*
  45.  * A data structure of the following type holds window-manager-related
  46.  * information for each top-level window in an application.
  47.  */
  48.  
  49. typedef struct TkWmInfo {
  50.     TkWindow *winPtr;        /* Pointer to main Tk information for
  51.                  * this window. */
  52.     HWND wrapper;        /* This is the decorative frame window
  53.                  * created by the window manager to wrap
  54.                  * a toplevel window.  This window is
  55.                  * a direct child of the root window. */
  56.     Tk_Uid titleUid;        /* Title to display in window caption.  If
  57.                  * NULL, use name of widget. */
  58.     Tk_Uid iconName;        /* Name to display in icon. */
  59.     TkWindow *masterPtr;    /* Master window for TRANSIENT_FOR property,
  60.                  * or NULL. */
  61.     XWMHints hints;        /* Various pieces of information for
  62.                  * window manager. */
  63.     char *leaderName;        /* Path name of leader of window group
  64.                  * (corresponds to hints.window_group).
  65.                  * Malloc-ed. Note:  this field doesn't
  66.                  * get updated if leader is destroyed. */
  67.     Tk_Window icon;        /* Window to use as icon for this window,
  68.                  * or NULL. */
  69.     Tk_Window iconFor;        /* Window for which this window is icon, or
  70.                  * NULL if this isn't an icon for anyone. */
  71.  
  72.     /*
  73.      * Information used to construct an XSizeHints structure for
  74.      * the window manager:
  75.      */
  76.  
  77.     int defMinWidth, defMinHeight, defMaxWidth, defMaxHeight;
  78.                 /* Default resize limits given by system. */
  79.     int sizeHintsFlags;        /* Flags word for XSizeHints structure.
  80.                  * If the PBaseSize flag is set then the
  81.                  * window is gridded;  otherwise it isn't
  82.                  * gridded. */
  83.     int minWidth, minHeight;    /* Minimum dimensions of window, in
  84.                  * grid units, not pixels. */
  85.     int maxWidth, maxHeight;    /* Maximum dimensions of window, in
  86.                  * grid units, not pixels, or 0 to default. */
  87.     Tk_Window gridWin;        /* Identifies the window that controls
  88.                  * gridding for this top-level, or NULL if
  89.                  * the top-level isn't currently gridded. */
  90.     int widthInc, heightInc;    /* Increments for size changes (# pixels
  91.                  * per step). */
  92.     struct {
  93.     int x;    /* numerator */
  94.     int y;  /* denominator */
  95.     } minAspect, maxAspect;    /* Min/max aspect ratios for window. */
  96.     int reqGridWidth, reqGridHeight;
  97.                 /* The dimensions of the window (in
  98.                  * grid units) requested through
  99.                  * the geometry manager. */
  100.     int gravity;        /* Desired window gravity. */
  101.  
  102.     /*
  103.      * Information used to manage the size and location of a window.
  104.      */
  105.  
  106.     int width, height;        /* Desired dimensions of window, specified
  107.                  * in grid units.  These values are
  108.                  * set by the "wm geometry" command and by
  109.                  * ConfigureNotify events (for when wm
  110.                  * resizes window).  -1 means user hasn't
  111.                  * requested dimensions. */
  112.     int x, y;            /* Desired X and Y coordinates for window.
  113.                  * These values are set by "wm geometry",
  114.                  * plus by ConfigureNotify events (when wm
  115.                  * moves window).  These numbers are
  116.                  * different than the numbers stored in
  117.                  * winPtr->changes because (a) they could be
  118.                  * measured from the right or bottom edge
  119.                  * of the screen (see WM_NEGATIVE_X and
  120.                  * WM_NEGATIVE_Y flags) and (b) if the window
  121.                  * has been reparented then they refer to the
  122.                  * parent rather than the window itself. */
  123.     int borderWidth, borderHeight;
  124.                 /* Width and height of window dressing, in
  125.                  * pixels for the current style/exStyle.  This
  126.                  * includes the border on both sides of the
  127.                  * window. */
  128.     int configWidth, configHeight;
  129.                 /* Dimensions passed to last request that we
  130.                  * issued to change geometry of window.  Used
  131.                  * to eliminate redundant resize operations. */
  132.     HMENU hMenu;        /* the hMenu associated with this menu */
  133.     DWORD style, exStyle;    /* Style flags for the wrapper window. */
  134.  
  135.     /*
  136.      * List of children of the toplevel which have private colormaps.
  137.      */
  138.  
  139.     TkWindow **cmapList;    /* Array of window with private colormaps. */
  140.     int cmapCount;        /* Number of windows in array. */
  141.  
  142.     /*
  143.      * Miscellaneous information.
  144.      */
  145.  
  146.     ProtocolHandler *protPtr;    /* First in list of protocol handlers for
  147.                  * this window (NULL means none). */
  148.     int cmdArgc;        /* Number of elements in cmdArgv below. */
  149.     char **cmdArgv;        /* Array of strings to store in the
  150.                  * WM_COMMAND property.  NULL means nothing
  151.                  * available. */
  152.     char *clientMachine;    /* String to store in WM_CLIENT_MACHINE
  153.                  * property, or NULL. */
  154.     int flags;            /* Miscellaneous flags, defined below. */
  155.     struct TkWmInfo *nextPtr;    /* Next in list of all top-level windows. */
  156. } WmInfo;
  157.  
  158. /*
  159.  * Flag values for WmInfo structures:
  160.  *
  161.  * WM_NEVER_MAPPED -        non-zero means window has never been
  162.  *                mapped;  need to update all info when
  163.  *                window is first mapped.
  164.  * WM_UPDATE_PENDING -        non-zero means a call to UpdateGeometryInfo
  165.  *                has already been scheduled for this
  166.  *                window;  no need to schedule another one.
  167.  * WM_NEGATIVE_X -        non-zero means x-coordinate is measured in
  168.  *                pixels from right edge of screen, rather
  169.  *                than from left edge.
  170.  * WM_NEGATIVE_Y -        non-zero means y-coordinate is measured in
  171.  *                pixels up from bottom of screen, rather than
  172.  *                down from top.
  173.  * WM_UPDATE_SIZE_HINTS -    non-zero means that new size hints need to be
  174.  *                propagated to window manager.
  175.  * WM_SYNC_PENDING -        set to non-zero while waiting for the window
  176.  *                manager to respond to some state change.
  177.  * WM_MOVE_PENDING -        non-zero means the application has requested
  178.  *                a new position for the window, but it hasn't
  179.  *                been reflected through the window manager
  180.  *                yet.
  181.  * WM_COLORAMPS_EXPLICIT -    non-zero means the colormap windows were
  182.  *                set explicitly via "wm colormapwindows".
  183.  * WM_ADDED_TOPLEVEL_COLORMAP - non-zero means that when "wm colormapwindows"
  184.  *                was called the top-level itself wasn't
  185.  *                specified, so we added it implicitly at
  186.  *                the end of the list.
  187.  */
  188.  
  189. #define WM_NEVER_MAPPED            (1<<0)
  190. #define WM_UPDATE_PENDING        (1<<1)
  191. #define WM_NEGATIVE_X            (1<<2)
  192. #define WM_NEGATIVE_Y            (1<<3)
  193. #define WM_UPDATE_SIZE_HINTS        (1<<4)
  194. #define WM_SYNC_PENDING            (1<<5)
  195. #define WM_CREATE_PENDING        (1<<6)
  196. #define WM_MOVE_PENDING            (1<<7)
  197. #define WM_COLORMAPS_EXPLICIT        (1<<8)
  198. #define WM_ADDED_TOPLEVEL_COLORMAP    (1<<9)
  199. #define WM_WIDTH_NOT_RESIZABLE        (1<<10)
  200. #define WM_HEIGHT_NOT_RESIZABLE        (1<<11)
  201.  
  202. /*
  203.  * Window styles for various types of toplevel windows.
  204.  */
  205.  
  206. #define WM_OVERRIDE_STYLE (WS_POPUP|WS_CLIPCHILDREN|CS_DBLCLKS)
  207. #define EX_OVERRIDE_STYLE (WS_EX_TOOLWINDOW)
  208.  
  209. #define WM_TOPLEVEL_STYLE (WS_OVERLAPPEDWINDOW|WS_CLIPCHILDREN|CS_DBLCLKS)
  210. #define EX_TOPLEVEL_STYLE (0)
  211.  
  212. #define WM_TRANSIENT_STYLE \
  213.         (WS_POPUP|WS_CAPTION|WS_SYSMENU|WS_CLIPSIBLINGS|CS_DBLCLKS)
  214. #define EX_TRANSIENT_STYLE (WS_EX_TOOLWINDOW | WS_EX_DLGMODALFRAME)
  215.  
  216. /*
  217.  * This module keeps a list of all top-level windows.
  218.  */
  219.  
  220. static WmInfo *firstWmPtr = NULL;    /* Points to first top-level window. */
  221. static WmInfo *foregroundWmPtr = NULL; /* Points to the foreground window. */
  222.  
  223. /*
  224.  * The variable below is used to enable or disable tracing in this
  225.  * module.  If tracing is enabled, then information is printed on
  226.  * standard output about interesting interactions with the window
  227.  * manager.
  228.  */
  229.  
  230. static int wmTracing = 0;
  231.  
  232. /*
  233.  * The following structure is the official type record for geometry
  234.  * management of top-level windows.
  235.  */
  236.  
  237. static void        TopLevelReqProc(ClientData dummy, Tk_Window tkwin);
  238.  
  239. static Tk_GeomMgr wmMgrType = {
  240.     "wm",                /* name */
  241.     TopLevelReqProc,            /* requestProc */
  242.     (Tk_GeomLostSlaveProc *) NULL,    /* lostSlaveProc */
  243. };
  244.  
  245. /*
  246.  * Global system palette.  This value always refers to the currently
  247.  * installed foreground logical palette.
  248.  */
  249.  
  250. static HPALETTE systemPalette = NULL;
  251.  
  252. /*
  253.  * Window that is being constructed.  This value is set immediately
  254.  * before a call to CreateWindowEx, and is used by SetLimits.
  255.  * This is a gross hack needed to work around Windows brain damage
  256.  * where it sends the WM_GETMINMAXINFO message before the WM_CREATE
  257.  * window.
  258.  */
  259.  
  260. static TkWindow *createWindow = NULL;
  261.  
  262. /*
  263.  * Flag indicating whether this module has been initialized yet.
  264.  */
  265.  
  266. static int initialized = 0;
  267.  
  268. /*
  269.  * Class for toplevel windows.
  270.  */
  271.  
  272. static WNDCLASS toplevelClass;
  273.  
  274. /*
  275.  * This flag is cleared when the first window is mapped in a non-iconic
  276.  * state.
  277.  */
  278.  
  279. static int firstWindow = 1;
  280.  
  281. /*
  282.  * Forward declarations for procedures defined in this file:
  283.  */
  284.  
  285. static void        ConfigureEvent _ANSI_ARGS_((TkWindow *winPtr,
  286.                 XConfigureEvent *eventPtr));
  287. static void        ConfigureTopLevel _ANSI_ARGS_((WINDOWPOS *pos));
  288. static void        DeiconifyWindow _ANSI_ARGS_((TkWindow *winPtr));
  289. static void        GenerateConfigureNotify _ANSI_ARGS_((
  290.                 TkWindow *winPtr));
  291. static void        GetMaxSize _ANSI_ARGS_((WmInfo *wmPtr,
  292.                 int *maxWidthPtr, int *maxHeightPtr));
  293. static void        GetMinSize _ANSI_ARGS_((WmInfo *wmPtr,
  294.                 int *minWidthPtr, int *minHeightPtr));
  295. static TkWindow *    GetTopLevel _ANSI_ARGS_((HWND hwnd));
  296. static void        IconifyWindow _ANSI_ARGS_((TkWindow *winPtr));
  297. static void        InitWm _ANSI_ARGS_((void));
  298. static int        InstallColormaps _ANSI_ARGS_((HWND hwnd, int message,
  299.                 int isForemost));
  300. static void        InvalidateSubTree _ANSI_ARGS_((TkWindow *winPtr,
  301.                 Colormap colormap));
  302. static int        ParseGeometry _ANSI_ARGS_((Tcl_Interp *interp,
  303.                 char *string, TkWindow *winPtr));
  304. static void        RefreshColormap _ANSI_ARGS_((Colormap colormap));
  305. static void        SetLimits _ANSI_ARGS_((HWND hwnd, MINMAXINFO *info));
  306. static LRESULT CALLBACK    TopLevelProc _ANSI_ARGS_((HWND hwnd, UINT message,
  307.                 WPARAM wParam, LPARAM lParam));
  308. static void        TopLevelEventProc _ANSI_ARGS_((ClientData clientData,
  309.                 XEvent *eventPtr));
  310. static void        TopLevelReqProc _ANSI_ARGS_((ClientData dummy,
  311.                 Tk_Window tkwin));
  312. static void        UpdateGeometryInfo _ANSI_ARGS_((
  313.                 ClientData clientData));
  314. static void        UpdateWrapper _ANSI_ARGS_((TkWindow *winPtr));
  315. static LRESULT CALLBACK    WmProc _ANSI_ARGS_((HWND hwnd, UINT message,
  316.                 WPARAM wParam, LPARAM lParam));
  317.  
  318. /*
  319.  *----------------------------------------------------------------------
  320.  *
  321.  * InitWm --
  322.  *
  323.  *    This routine creates the Wm toplevel decorative frame class.
  324.  *
  325.  * Results:
  326.  *    None.
  327.  *
  328.  * Side effects:
  329.  *    Registers a new window class.
  330.  *
  331.  *----------------------------------------------------------------------
  332.  */
  333.  
  334. static void
  335. InitWm(void)
  336. {
  337.     if (initialized) {
  338.         return;
  339.     }
  340.     initialized = 1;
  341.  
  342.     toplevelClass.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC;
  343.     toplevelClass.cbClsExtra = 0;
  344.     toplevelClass.cbWndExtra = 0;
  345.     toplevelClass.hInstance = Tk_GetHINSTANCE();
  346.     toplevelClass.hbrBackground = NULL;
  347.     toplevelClass.lpszMenuName = NULL;
  348.     toplevelClass.lpszClassName = TK_WIN_TOPLEVEL_CLASS_NAME;
  349.     toplevelClass.lpfnWndProc = WmProc;
  350.     toplevelClass.hIcon = LoadIcon(TkWinGetTkModule(), "tk");
  351.     toplevelClass.hCursor = LoadCursor(NULL, IDC_ARROW);
  352.  
  353.     if (!RegisterClass(&toplevelClass)) {
  354.     panic("Unable to register TkTopLevel class");
  355.     }
  356. }
  357.  
  358. /*
  359.  *----------------------------------------------------------------------
  360.  *
  361.  * GetTopLevel --
  362.  *
  363.  *    This function retrieves the TkWindow associated with the
  364.  *    given HWND.
  365.  *
  366.  * Results:
  367.  *    Returns the matching TkWindow.
  368.  *
  369.  * Side effects:
  370.  *    None.
  371.  *
  372.  *----------------------------------------------------------------------
  373.  */
  374.  
  375. static TkWindow *
  376. GetTopLevel(hwnd)
  377.     HWND hwnd;
  378. {
  379.     /*
  380.      * If this function is called before the CreateWindowEx call
  381.      * has completed, then the user data slot will not have been
  382.      * set yet, so we use the global createWindow variable.
  383.      */
  384.  
  385.     if (createWindow) {
  386.     return createWindow;
  387.     }
  388.     return (TkWindow *) GetWindowLong(hwnd, GWL_USERDATA);
  389. }
  390.  
  391. /*
  392.  *----------------------------------------------------------------------
  393.  *
  394.  * SetLimits --
  395.  *
  396.  *    Updates the minimum and maximum window size constraints.
  397.  *
  398.  * Results:
  399.  *    None.
  400.  *
  401.  * Side effects:
  402.  *    Changes the values of the info pointer to reflect the current
  403.  *    minimum and maximum size values.
  404.  *
  405.  *----------------------------------------------------------------------
  406.  */
  407.  
  408. static void
  409. SetLimits(hwnd, info)
  410.     HWND hwnd;
  411.     MINMAXINFO *info;
  412. {
  413.     register WmInfo *wmPtr;
  414.     int maxWidth, maxHeight;
  415.     int minWidth, minHeight;
  416.     int base;
  417.     TkWindow *winPtr = GetTopLevel(hwnd);
  418.  
  419.     if (winPtr == NULL) {
  420.     return;
  421.     }
  422.  
  423.     wmPtr = winPtr->wmInfoPtr;
  424.     
  425.     /*
  426.      * Copy latest constraint info.
  427.      */
  428.  
  429.     wmPtr->defMinWidth = info->ptMinTrackSize.x;
  430.     wmPtr->defMinHeight = info->ptMinTrackSize.y;
  431.     wmPtr->defMaxWidth = info->ptMaxTrackSize.x;
  432.     wmPtr->defMaxHeight = info->ptMaxTrackSize.y;
  433.     
  434.     GetMaxSize(wmPtr, &maxWidth, &maxHeight);
  435.     GetMinSize(wmPtr, &minWidth, &minHeight);
  436.  
  437.     if (wmPtr->gridWin != NULL) {
  438.     base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
  439.     if (base < 0) {
  440.         base = 0;
  441.     }
  442.     base += wmPtr->borderWidth;
  443.     info->ptMinTrackSize.x = base + (minWidth * wmPtr->widthInc);
  444.     info->ptMaxTrackSize.x = base + (maxWidth * wmPtr->widthInc);
  445.  
  446.     base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
  447.     if (base < 0) {
  448.         base = 0;
  449.     }
  450.     base += wmPtr->borderHeight;
  451.     info->ptMinTrackSize.y = base + (minHeight * wmPtr->heightInc);
  452.     info->ptMaxTrackSize.y = base + (maxHeight * wmPtr->heightInc);
  453.     } else {
  454.     info->ptMaxTrackSize.x = maxWidth + wmPtr->borderWidth;
  455.     info->ptMaxTrackSize.y = maxHeight + wmPtr->borderHeight;
  456.     info->ptMinTrackSize.x = minWidth + wmPtr->borderWidth;
  457.     info->ptMinTrackSize.y = minHeight + wmPtr->borderHeight;
  458.     }
  459.  
  460.     /*
  461.      * If the window isn't supposed to be resizable, then set the
  462.      * minimum and maximum dimensions to be the same as the current size.
  463.      */
  464.  
  465.     if (!(wmPtr->flags & WM_SYNC_PENDING)) {
  466.     if (wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) {
  467.         info->ptMinTrackSize.x = winPtr->changes.width
  468.         + wmPtr->borderWidth;
  469.         info->ptMaxTrackSize.x = info->ptMinTrackSize.x;
  470.     }
  471.     if (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE) {
  472.         info->ptMinTrackSize.y = winPtr->changes.height 
  473.         + wmPtr->borderHeight;
  474.         info->ptMaxTrackSize.y = info->ptMinTrackSize.y;
  475.     }
  476.     }
  477. }
  478.  
  479. /*
  480.  *----------------------------------------------------------------------
  481.  *
  482.  * TkWinWmCleanup --
  483.  *
  484.  *    Unregisters classes registered by the window manager. This is
  485.  *    called from the DLL main entry point when the DLL is unloaded.
  486.  *
  487.  * Results:
  488.  *    None.
  489.  *
  490.  * Side effects:
  491.  *    The window classes are discarded.
  492.  *
  493.  *----------------------------------------------------------------------
  494.  */
  495.  
  496. void
  497. TkWinWmCleanup(hInstance)
  498.     HINSTANCE hInstance;
  499. {
  500.     if (!initialized) {
  501.         return;
  502.     }
  503.     initialized = 0;
  504.     
  505.     UnregisterClass(TK_WIN_TOPLEVEL_CLASS_NAME, hInstance);
  506. }
  507.  
  508. /*
  509.  *--------------------------------------------------------------
  510.  *
  511.  * TkWmNewWindow --
  512.  *
  513.  *    This procedure is invoked whenever a new top-level
  514.  *    window is created.  Its job is to initialize the WmInfo
  515.  *    structure for the window.
  516.  *
  517.  * Results:
  518.  *    None.
  519.  *
  520.  * Side effects:
  521.  *    A WmInfo structure gets allocated and initialized.
  522.  *
  523.  *--------------------------------------------------------------
  524.  */
  525.  
  526. void
  527. TkWmNewWindow(winPtr)
  528.     TkWindow *winPtr;        /* Newly-created top-level window. */
  529. {
  530.     register WmInfo *wmPtr;
  531.  
  532.     wmPtr = (WmInfo *) ckalloc(sizeof(WmInfo));
  533.     winPtr->wmInfoPtr = wmPtr;
  534.     wmPtr->winPtr = winPtr;
  535.     wmPtr->wrapper = NULL;
  536.     wmPtr->titleUid = NULL;
  537.     wmPtr->iconName = NULL;
  538.     wmPtr->masterPtr = NULL;
  539.     wmPtr->hints.flags = InputHint | StateHint;
  540.     wmPtr->hints.input = True;
  541.     wmPtr->hints.initial_state = NormalState;
  542.     wmPtr->hints.icon_pixmap = None;
  543.     wmPtr->hints.icon_window = None;
  544.     wmPtr->hints.icon_x = wmPtr->hints.icon_y = 0;
  545.     wmPtr->hints.icon_mask = None;
  546.     wmPtr->hints.window_group = None;
  547.     wmPtr->leaderName = NULL;
  548.     wmPtr->icon = NULL;
  549.     wmPtr->iconFor = NULL;
  550.     wmPtr->sizeHintsFlags = 0;
  551.  
  552.     /*
  553.      * Default the maximum dimensions to the size of the display.
  554.      */
  555.  
  556.     wmPtr->defMinWidth = wmPtr->defMinHeight = 0;
  557.     wmPtr->defMaxWidth = DisplayWidth(winPtr->display,
  558.         winPtr->screenNum);
  559.     wmPtr->defMaxHeight = DisplayHeight(winPtr->display,
  560.         winPtr->screenNum);
  561.     wmPtr->minWidth = wmPtr->minHeight = 1;
  562.     wmPtr->maxWidth = wmPtr->maxHeight = 0;
  563.     wmPtr->gridWin = NULL;
  564.     wmPtr->widthInc = wmPtr->heightInc = 1;
  565.     wmPtr->minAspect.x = wmPtr->minAspect.y = 1;
  566.     wmPtr->maxAspect.x = wmPtr->maxAspect.y = 1;
  567.     wmPtr->reqGridWidth = wmPtr->reqGridHeight = -1;
  568.     wmPtr->gravity = NorthWestGravity;
  569.     wmPtr->width = -1;
  570.     wmPtr->height = -1;
  571.     wmPtr->hMenu = NULL;
  572.     wmPtr->x = winPtr->changes.x;
  573.     wmPtr->y = winPtr->changes.y;
  574.     wmPtr->borderWidth = 0;
  575.     wmPtr->borderHeight = 0;
  576.     
  577.     wmPtr->cmapList = NULL;
  578.     wmPtr->cmapCount = 0;
  579.  
  580.     wmPtr->configWidth = -1;
  581.     wmPtr->configHeight = -1;
  582.     wmPtr->protPtr = NULL;
  583.     wmPtr->cmdArgv = NULL;
  584.     wmPtr->clientMachine = NULL;
  585.     wmPtr->flags = WM_NEVER_MAPPED;
  586.     wmPtr->nextPtr = firstWmPtr;
  587.     firstWmPtr = wmPtr;
  588.  
  589.     /*
  590.      * Tk must monitor structure events for top-level windows, in order
  591.      * to detect size and position changes caused by window managers.
  592.      */
  593.  
  594.     Tk_CreateEventHandler((Tk_Window) winPtr, StructureNotifyMask,
  595.         TopLevelEventProc, (ClientData) winPtr);
  596.  
  597.     /*
  598.      * Arrange for geometry requests to be reflected from the window
  599.      * to the window manager.
  600.      */
  601.  
  602.     Tk_ManageGeometry((Tk_Window) winPtr, &wmMgrType, (ClientData) 0);
  603. }
  604.  
  605. /*
  606.  *----------------------------------------------------------------------
  607.  *
  608.  * UpdateWrapper --
  609.  *
  610.  *    This function creates the wrapper window that contains the
  611.  *    window decorations and menus for a toplevel.  This function
  612.  *    may be called after a window is mapped to change the window
  613.  *    style.
  614.  *
  615.  * Results:
  616.  *    None.
  617.  *
  618.  * Side effects:
  619.  *    Destroys any old wrapper window and replaces it with a newly
  620.  *    created wrapper.
  621.  *
  622.  *----------------------------------------------------------------------
  623.  */
  624.  
  625. static void
  626. UpdateWrapper(winPtr)
  627.     TkWindow *winPtr;        /* Top-level window to redecorate. */
  628. {
  629.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  630.     HWND parentHWND = NULL, oldWrapper;
  631.     HWND child = TkWinGetHWND(winPtr->window);
  632.     int x, y, width, height, state;
  633.     WINDOWPLACEMENT place;
  634.  
  635.     parentHWND = NULL;
  636.     child = TkWinGetHWND(winPtr->window); 
  637.  
  638.     if (winPtr->flags & TK_EMBEDDED) {
  639.     wmPtr->wrapper = (HWND) winPtr->privatePtr;
  640.     if (wmPtr->wrapper == NULL) {
  641.         panic("TkWmMapWindow: Cannot find container window");
  642.     }
  643.     if (!IsWindow(wmPtr->wrapper)) {
  644.         panic("TkWmMapWindow: Container was destroyed");
  645.     }
  646.  
  647.     } else {
  648.     /*
  649.      * Pick the decorative frame style.  Override redirect windows get
  650.      * created as undecorated popups.  Transient windows get a modal
  651.      * dialog frame.  Neither override, nor transient windows appear in
  652.      * the Win95 taskbar.  Note that a transient window does not resize
  653.      * by default, so we need to explicitly add the WS_THICKFRAME style
  654.      * if we want it to be resizeable.
  655.      */
  656.     
  657.     if (winPtr->atts.override_redirect) {
  658.         wmPtr->style = WM_OVERRIDE_STYLE;
  659.         wmPtr->exStyle = EX_OVERRIDE_STYLE;
  660.     } else if (wmPtr->masterPtr) {
  661.         wmPtr->style = WM_TRANSIENT_STYLE;
  662.         wmPtr->exStyle = EX_TRANSIENT_STYLE;
  663.         parentHWND = Tk_GetHWND(Tk_WindowId(wmPtr->masterPtr));
  664.         if (! ((wmPtr->flags & WM_WIDTH_NOT_RESIZABLE) && 
  665.             (wmPtr->flags & WM_HEIGHT_NOT_RESIZABLE))) {
  666.         wmPtr->style |= WS_THICKFRAME;
  667.         }
  668.     } else {
  669.         wmPtr->style = WM_TOPLEVEL_STYLE;
  670.         wmPtr->exStyle = EX_TOPLEVEL_STYLE;
  671.     }
  672.  
  673.     /*
  674.      * Compute the geometry of the parent and child windows.
  675.      */
  676.  
  677.     wmPtr->flags |= WM_CREATE_PENDING|WM_MOVE_PENDING;
  678.     UpdateGeometryInfo((ClientData)winPtr);
  679.     wmPtr->flags &= ~(WM_CREATE_PENDING|WM_MOVE_PENDING);
  680.  
  681.     width = wmPtr->borderWidth + winPtr->changes.width;
  682.     height = wmPtr->borderHeight + winPtr->changes.height;
  683.  
  684.     /*
  685.      * Set the initial position from the user or program specified
  686.      * location.  If nothing has been specified, then let the system
  687.      * pick a location.
  688.      */
  689.  
  690.    
  691.     if (!(wmPtr->sizeHintsFlags & (USPosition | PPosition))
  692.         && (wmPtr->flags & WM_NEVER_MAPPED)) {
  693.         x = CW_USEDEFAULT;
  694.         y = CW_USEDEFAULT;
  695.     } else {
  696.         x = winPtr->changes.x;
  697.         y = winPtr->changes.y;
  698.     }
  699.  
  700.     /*
  701.      * Create the containing window, and set the user data to point
  702.      * to the TkWindow.
  703.      */
  704.  
  705.     createWindow = winPtr;
  706.     wmPtr->wrapper = CreateWindowEx(wmPtr->exStyle,
  707.         TK_WIN_TOPLEVEL_CLASS_NAME,
  708.         wmPtr->titleUid, wmPtr->style, x, y, width, height,
  709.         parentHWND, NULL, Tk_GetHINSTANCE(), NULL);
  710.     SetWindowLong(wmPtr->wrapper, GWL_USERDATA, (LONG) winPtr);
  711.     createWindow = NULL;
  712.  
  713.     place.length = sizeof(WINDOWPLACEMENT);
  714.     GetWindowPlacement(wmPtr->wrapper, &place);
  715.     wmPtr->x = place.rcNormalPosition.left;
  716.     wmPtr->y = place.rcNormalPosition.top;
  717.  
  718.     TkInstallFrameMenu((Tk_Window) winPtr);
  719.     }
  720.  
  721.     /*
  722.      * Now we need to reparent the contained window and set its
  723.      * style appropriately.  Be sure to update the style first so that
  724.      * Windows doesn't try to set the focus to the child window.
  725.      */
  726.  
  727.     SetWindowLong(child, GWL_STYLE,
  728.         WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
  729.     if (winPtr->flags & TK_EMBEDDED) {
  730.     SetWindowLong(child, GWL_WNDPROC, (LONG) TopLevelProc);
  731.     }
  732.     oldWrapper = SetParent(child, wmPtr->wrapper);
  733.     if (oldWrapper && (oldWrapper != wmPtr->wrapper) 
  734.         && (oldWrapper != GetDesktopWindow())) {
  735.     SetWindowLong(oldWrapper, GWL_USERDATA, (LONG) NULL);
  736.     DestroyWindow(oldWrapper);
  737.     }
  738.     wmPtr->flags &= ~WM_NEVER_MAPPED;
  739.     SendMessage(wmPtr->wrapper, TK_ATTACHWINDOW, (WPARAM) child, 0);
  740.  
  741.     /*
  742.      * Force an initial transition from withdrawn to the real
  743.      * initial state.     
  744.      */
  745.  
  746.     state = wmPtr->hints.initial_state;
  747.     wmPtr->hints.initial_state = WithdrawnState;
  748.     TkpWmSetState(winPtr, state);
  749.  
  750.     /*
  751.      * If we are embedded then force a mapping of the window now,
  752.      * because we do not necessarily own the wrapper and may not
  753.      * get another opportunity to map ourselves. We should not be
  754.      * in either iconified or zoomed states when we get here, so
  755.      * it is safe to just check for TK_EMBEDDED without checking
  756.      * what state we are supposed to be in (default to NormalState).
  757.      */
  758.  
  759.     if (winPtr->flags & TK_EMBEDDED) {
  760.     XMapWindow(winPtr->display, winPtr->window);
  761.     }
  762.  
  763.     /*
  764.      * Set up menus on the wrapper if required.
  765.      */
  766.         
  767.     if (wmPtr->hMenu != NULL) {
  768.     wmPtr->flags = WM_SYNC_PENDING;
  769.     SetMenu(wmPtr->wrapper, wmPtr->hMenu);
  770.     wmPtr->flags &= ~WM_SYNC_PENDING;
  771.     }
  772.  
  773.     /*
  774.      * If this is the first window created by the application, then
  775.      * we should activate the initial window.
  776.      */
  777.  
  778.     if (firstWindow) {
  779.     firstWindow = 0;
  780.     SetActiveWindow(wmPtr->wrapper);
  781.     }
  782. }
  783.  
  784. /*
  785.  *--------------------------------------------------------------
  786.  *
  787.  * TkWmMapWindow --
  788.  *
  789.  *    This procedure is invoked to map a top-level window.  This
  790.  *    module gets a chance to update all window-manager-related
  791.  *    information in properties before the window manager sees
  792.  *    the map event and checks the properties.  It also gets to
  793.  *    decide whether or not to even map the window after all.
  794.  *
  795.  * Results:
  796.  *    None.
  797.  *
  798.  * Side effects:
  799.  *    Properties of winPtr may get updated to provide up-to-date
  800.  *    information to the window manager.  The window may also get
  801.  *    mapped, but it may not be if this procedure decides that
  802.  *    isn't appropriate (e.g. because the window is withdrawn).
  803.  *
  804.  *--------------------------------------------------------------
  805.  */
  806.  
  807. void
  808. TkWmMapWindow(winPtr)
  809.     TkWindow *winPtr;        /* Top-level window that's about to
  810.                  * be mapped. */
  811. {
  812.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  813.  
  814.     if (!initialized) {
  815.     InitWm();
  816.     }
  817.  
  818.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  819.     if (wmPtr->hints.initial_state == WithdrawnState) {
  820.         return;
  821.     }
  822.  
  823.     /*
  824.      * Map the window in either the iconified or normal state.  Note that
  825.      * we only send a map event if the window is in the normal state.
  826.      */
  827.  
  828.     TkpWmSetState(winPtr, wmPtr->hints.initial_state);
  829.     }
  830.  
  831.     /*
  832.      * This is the first time this window has ever been mapped.
  833.      * Store all the window-manager-related information for the
  834.      * window.
  835.      */
  836.  
  837.     if (wmPtr->titleUid == NULL) {
  838.     wmPtr->titleUid = winPtr->nameUid;
  839.     }
  840.     UpdateWrapper(winPtr);
  841. }
  842.  
  843. /*
  844.  *--------------------------------------------------------------
  845.  *
  846.  * TkWmUnmapWindow --
  847.  *
  848.  *    This procedure is invoked to unmap a top-level window.  The
  849.  *    only thing it does special is unmap the decorative frame before
  850.  *    unmapping the toplevel window.
  851.  *
  852.  * Results:
  853.  *    None.
  854.  *
  855.  * Side effects:
  856.  *    Unmaps the decorative frame and the window.
  857.  *
  858.  *--------------------------------------------------------------
  859.  */
  860.  
  861. void
  862. TkWmUnmapWindow(winPtr)
  863.     TkWindow *winPtr;        /* Top-level window that's about to
  864.                  * be unmapped. */
  865. {
  866.     TkpWmSetState(winPtr, WithdrawnState);
  867. }
  868.  
  869. /*
  870.  *----------------------------------------------------------------------
  871.  *
  872.  * TkpWmSetState --
  873.  *
  874.  *    Sets the window manager state for the wrapper window of a
  875.  *    given toplevel window.
  876.  *
  877.  * Results:
  878.  *    None.
  879.  *
  880.  * Side effects:
  881.  *    May maximize, minimize, restore, or withdraw a window.
  882.  *
  883.  *----------------------------------------------------------------------
  884.  */
  885.  
  886. void
  887. TkpWmSetState(winPtr, state)
  888.      TkWindow *winPtr;        /* Toplevel window to operate on. */
  889.      int state;            /* One of IconicState, ZoomState, NormalState,
  890.                  * or WithdrawnState. */
  891. {
  892.     WmInfo *wmPtr = winPtr->wmInfoPtr;
  893.     int cmd;
  894.     
  895.     if (wmPtr->flags & WM_NEVER_MAPPED) {
  896.     wmPtr->hints.initial_state = state;
  897.     return;
  898.     }
  899.  
  900.     wmPtr->flags |= WM_SYNC_PENDING;
  901.     if (state == WithdrawnState) {
  902.     cmd = SW_HIDE;
  903.     } else if (state == IconicState) {
  904.     cmd = SW_SHOWMINNOACTIVE;
  905.     } else if (state == NormalState) {
  906.     cmd = SW_SHOWNOACTIVATE;
  907.     } else if (state == ZoomState) {
  908.     cmd = SW_SHOWMAXIMIZED;
  909.     }
  910.     ShowWindow(wmPtr->wrapper, cmd);
  911.     wmPtr->flags &= ~WM_SYNC_PENDING;
  912. }
  913.  
  914. /*
  915.  *--------------------------------------------------------------
  916.  *
  917.  * TkWmDeadWindow --
  918.  *
  919.  *    This procedure is invoked when a top-level window is
  920.  *    about to be deleted.  It cleans up the wm-related data
  921.  *    structures for the window.
  922.  *
  923.  * Results:
  924.  *    None.
  925.  *
  926.  * Side effects:
  927.  *    The WmInfo structure for winPtr gets freed up.
  928.  *
  929.  *--------------------------------------------------------------
  930.  */
  931.  
  932. void
  933. TkWmDeadWindow(winPtr)
  934.     TkWindow *winPtr;        /* Top-level window that's being deleted. */
  935. {
  936.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  937.     WmInfo *wmPtr2;
  938.  
  939.     if (wmPtr == NULL) {
  940.     return;
  941.     }
  942.  
  943.     /*
  944.      * Clean up event related window info.
  945.      */
  946.  
  947.     if (firstWmPtr == wmPtr) {
  948.     firstWmPtr = wmPtr->nextPtr;
  949.     } else {
  950.     register WmInfo *prevPtr;
  951.     for (prevPtr = firstWmPtr; ; prevPtr = prevPtr->nextPtr) {
  952.         if (prevPtr == NULL) {
  953.         panic("couldn't unlink window in TkWmDeadWindow");
  954.         }
  955.         if (prevPtr->nextPtr == wmPtr) {
  956.         prevPtr->nextPtr = wmPtr->nextPtr;
  957.         break;
  958.         }
  959.     }
  960.     }
  961.  
  962.     /*
  963.      * Reset all transient windows whose master is the dead window.
  964.      */
  965.  
  966.     for (wmPtr2 = firstWmPtr; wmPtr2 != NULL; wmPtr2 = wmPtr2->nextPtr) {
  967.     if (wmPtr2->masterPtr == winPtr) {
  968.         wmPtr2->masterPtr = NULL;
  969.         if ((wmPtr2->wrapper != None)
  970.             && !(wmPtr2->flags & (WM_NEVER_MAPPED))) {
  971.         UpdateWrapper(wmPtr2->winPtr);
  972.         }
  973.     }
  974.     }
  975.     
  976.     if (wmPtr->hints.flags & IconPixmapHint) {
  977.     Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
  978.     }
  979.     if (wmPtr->hints.flags & IconMaskHint) {
  980.     Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
  981.     }
  982.     if (wmPtr->leaderName != NULL) {
  983.     ckfree(wmPtr->leaderName);
  984.     }
  985.     if (wmPtr->icon != NULL) {
  986.     wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  987.     wmPtr2->iconFor = NULL;
  988.     }
  989.     if (wmPtr->iconFor != NULL) {
  990.     wmPtr2 = ((TkWindow *) wmPtr->iconFor)->wmInfoPtr;
  991.     wmPtr2->icon = NULL;
  992.     wmPtr2->hints.flags &= ~IconWindowHint;
  993.     }
  994.     while (wmPtr->protPtr != NULL) {
  995.     ProtocolHandler *protPtr;
  996.  
  997.     protPtr = wmPtr->protPtr;
  998.     wmPtr->protPtr = protPtr->nextPtr;
  999.     Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
  1000.     }
  1001.     if (wmPtr->cmdArgv != NULL) {
  1002.     ckfree((char *) wmPtr->cmdArgv);
  1003.     }
  1004.     if (wmPtr->clientMachine != NULL) {
  1005.     ckfree((char *) wmPtr->clientMachine);
  1006.     }
  1007.     if (wmPtr->flags & WM_UPDATE_PENDING) {
  1008.     Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
  1009.     }
  1010.  
  1011.     /*
  1012.      * Destroy the decorative frame window.
  1013.      */
  1014.  
  1015.     if (!(winPtr->flags & TK_EMBEDDED)) {
  1016.     if (wmPtr->wrapper != NULL) {
  1017.         DestroyWindow(wmPtr->wrapper);
  1018.     } else {
  1019.         DestroyWindow(Tk_GetHWND(winPtr->window));
  1020.     }
  1021.     }
  1022.     ckfree((char *) wmPtr);
  1023.     winPtr->wmInfoPtr = NULL;
  1024. }
  1025.  
  1026. /*
  1027.  *--------------------------------------------------------------
  1028.  *
  1029.  * TkWmSetClass --
  1030.  *
  1031.  *    This procedure is invoked whenever a top-level window's
  1032.  *    class is changed.  If the window has been mapped then this
  1033.  *    procedure updates the window manager property for the
  1034.  *    class.  If the window hasn't been mapped, the update is
  1035.  *    deferred until just before the first mapping.
  1036.  *
  1037.  * Results:
  1038.  *    None.
  1039.  *
  1040.  * Side effects:
  1041.  *    A window property may get updated.
  1042.  *
  1043.  *--------------------------------------------------------------
  1044.  */
  1045.  
  1046. void
  1047. TkWmSetClass(winPtr)
  1048.     TkWindow *winPtr;        /* Newly-created top-level window. */
  1049. {
  1050.     return;
  1051. }
  1052.  
  1053. /*
  1054.  *----------------------------------------------------------------------
  1055.  *
  1056.  * Tk_WmCmd --
  1057.  *
  1058.  *    This procedure is invoked to process the "wm" Tcl command.
  1059.  *    See the user documentation for details on what it does.
  1060.  *
  1061.  * Results:
  1062.  *    A standard Tcl result.
  1063.  *
  1064.  * Side effects:
  1065.  *    See the user documentation.
  1066.  *
  1067.  *----------------------------------------------------------------------
  1068.  */
  1069.  
  1070.     /* ARGSUSED */
  1071. int
  1072. Tk_WmCmd(clientData, interp, argc, argv)
  1073.     ClientData clientData;    /* Main window associated with
  1074.                  * interpreter. */
  1075.     Tcl_Interp *interp;        /* Current interpreter. */
  1076.     int argc;            /* Number of arguments. */
  1077.     char **argv;        /* Argument strings. */
  1078. {
  1079.     Tk_Window tkwin = (Tk_Window) clientData;
  1080.     TkWindow *winPtr;
  1081.     register WmInfo *wmPtr;
  1082.     int c;
  1083.     size_t length;
  1084.  
  1085.     if (argc < 2) {
  1086.     wrongNumArgs:
  1087.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  1088.         argv[0], " option window ?arg ...?\"", (char *) NULL);
  1089.     return TCL_ERROR;
  1090.     }
  1091.     c = argv[1][0];
  1092.     length = strlen(argv[1]);
  1093.     if ((c == 't') && (strncmp(argv[1], "tracing", length) == 0)
  1094.         && (length >= 3)) {
  1095.     if ((argc != 2) && (argc != 3)) {
  1096.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1097.             argv[0], " tracing ?boolean?\"", (char *) NULL);
  1098.         return TCL_ERROR;
  1099.     }
  1100.     if (argc == 2) {
  1101.         interp->result = (wmTracing) ? "on" : "off";
  1102.         return TCL_OK;
  1103.     }
  1104.     return Tcl_GetBoolean(interp, argv[2], &wmTracing);
  1105.     }
  1106.  
  1107.     if (argc < 3) {
  1108.     goto wrongNumArgs;
  1109.     }
  1110.     winPtr = (TkWindow *) Tk_NameToWindow(interp, argv[2], tkwin);
  1111.     if (winPtr == NULL) {
  1112.     return TCL_ERROR;
  1113.     }
  1114.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  1115.     Tcl_AppendResult(interp, "window \"", winPtr->pathName,
  1116.         "\" isn't a top-level window", (char *) NULL);
  1117.     return TCL_ERROR;
  1118.     }
  1119.     wmPtr = winPtr->wmInfoPtr;
  1120.     if ((c == 'a') && (strncmp(argv[1], "aspect", length) == 0)) {
  1121.     int numer1, denom1, numer2, denom2;
  1122.  
  1123.     if ((argc != 3) && (argc != 7)) {
  1124.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1125.             argv[0], " aspect window ?minNumer minDenom ",
  1126.             "maxNumer maxDenom?\"", (char *) NULL);
  1127.         return TCL_ERROR;
  1128.     }
  1129.     if (argc == 3) {
  1130.         if (wmPtr->sizeHintsFlags & PAspect) {
  1131.         sprintf(interp->result, "%d %d %d %d", wmPtr->minAspect.x,
  1132.             wmPtr->minAspect.y, wmPtr->maxAspect.x,
  1133.             wmPtr->maxAspect.y);
  1134.         }
  1135.         return TCL_OK;
  1136.     }
  1137.     if (*argv[3] == '\0') {
  1138.         wmPtr->sizeHintsFlags &= ~PAspect;
  1139.     } else {
  1140.         if ((Tcl_GetInt(interp, argv[3], &numer1) != TCL_OK)
  1141.             || (Tcl_GetInt(interp, argv[4], &denom1) != TCL_OK)
  1142.             || (Tcl_GetInt(interp, argv[5], &numer2) != TCL_OK)
  1143.             || (Tcl_GetInt(interp, argv[6], &denom2) != TCL_OK)) {
  1144.         return TCL_ERROR;
  1145.         }
  1146.         if ((numer1 <= 0) || (denom1 <= 0) || (numer2 <= 0) ||
  1147.             (denom2 <= 0)) {
  1148.         interp->result = "aspect number can't be <= 0";
  1149.         return TCL_ERROR;
  1150.         }
  1151.         wmPtr->minAspect.x = numer1;
  1152.         wmPtr->minAspect.y = denom1;
  1153.         wmPtr->maxAspect.x = numer2;
  1154.         wmPtr->maxAspect.y = denom2;
  1155.         wmPtr->sizeHintsFlags |= PAspect;
  1156.     }
  1157.     goto updateGeom;
  1158.     } else if ((c == 'c') && (strncmp(argv[1], "client", length) == 0)
  1159.         && (length >= 2)) {
  1160.     if ((argc != 3) && (argc != 4)) {
  1161.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1162.             argv[0], " client window ?name?\"",
  1163.             (char *) NULL);
  1164.         return TCL_ERROR;
  1165.     }
  1166.     if (argc == 3) {
  1167.         if (wmPtr->clientMachine != NULL) {
  1168.         interp->result = wmPtr->clientMachine;
  1169.         }
  1170.         return TCL_OK;
  1171.     }
  1172.     if (argv[3][0] == 0) {
  1173.         if (wmPtr->clientMachine != NULL) {
  1174.         ckfree((char *) wmPtr->clientMachine);
  1175.         wmPtr->clientMachine = NULL;
  1176.         if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  1177.             XDeleteProperty(winPtr->display, winPtr->window,
  1178.                 Tk_InternAtom((Tk_Window) winPtr,
  1179.                 "WM_CLIENT_MACHINE"));
  1180.         }
  1181.         }
  1182.         return TCL_OK;
  1183.     }
  1184.     if (wmPtr->clientMachine != NULL) {
  1185.         ckfree((char *) wmPtr->clientMachine);
  1186.     }
  1187.     wmPtr->clientMachine = (char *)
  1188.         ckalloc((unsigned) (strlen(argv[3]) + 1));
  1189.     strcpy(wmPtr->clientMachine, argv[3]);
  1190.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  1191.         XTextProperty textProp;
  1192.         if (XStringListToTextProperty(&wmPtr->clientMachine, 1, &textProp)
  1193.             != 0) {
  1194.         XSetWMClientMachine(winPtr->display, winPtr->window,
  1195.             &textProp);
  1196.         XFree((char *) textProp.value);
  1197.         }
  1198.     }
  1199.     } else if ((c == 'c') && (strncmp(argv[1], "colormapwindows", length) == 0)
  1200.         && (length >= 3)) {
  1201.     TkWindow **cmapList;
  1202.     TkWindow *winPtr2;
  1203.     int i, windowArgc, gotToplevel;
  1204.     char **windowArgv;
  1205.  
  1206.     if ((argc != 3) && (argc != 4)) {
  1207.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1208.             argv[0], " colormapwindows window ?windowList?\"",
  1209.             (char *) NULL);
  1210.         return TCL_ERROR;
  1211.     }
  1212.     if (argc == 3) {
  1213.         Tk_MakeWindowExist((Tk_Window) winPtr);
  1214.         for (i = 0; i < wmPtr->cmapCount; i++) {
  1215.         if ((i == (wmPtr->cmapCount-1))
  1216.             && (wmPtr->flags & WM_ADDED_TOPLEVEL_COLORMAP)) {
  1217.             break;
  1218.         }
  1219.         Tcl_AppendElement(interp, wmPtr->cmapList[i]->pathName);
  1220.         }
  1221.         return TCL_OK;
  1222.     }
  1223.     if (Tcl_SplitList(interp, argv[3], &windowArgc, &windowArgv)
  1224.         != TCL_OK) {
  1225.         return TCL_ERROR;
  1226.     }
  1227.     cmapList = (TkWindow **) ckalloc((unsigned)
  1228.         ((windowArgc+1)*sizeof(TkWindow*)));
  1229.     for (i = 0; i < windowArgc; i++) {
  1230.         winPtr2 = (TkWindow *) Tk_NameToWindow(interp, windowArgv[i],
  1231.             tkwin);
  1232.         if (winPtr2 == NULL) {
  1233.         ckfree((char *) cmapList);
  1234.         ckfree((char *) windowArgv);
  1235.         return TCL_ERROR;
  1236.         }
  1237.         if (winPtr2 == winPtr) {
  1238.         gotToplevel = 1;
  1239.         }
  1240.         if (winPtr2->window == None) {
  1241.         Tk_MakeWindowExist((Tk_Window) winPtr2);
  1242.         }
  1243.         cmapList[i] = winPtr2;
  1244.     }
  1245.     if (!gotToplevel) {
  1246.         wmPtr->flags |= WM_ADDED_TOPLEVEL_COLORMAP;
  1247.         cmapList[windowArgc] = winPtr;
  1248.         windowArgc++;
  1249.     } else {
  1250.         wmPtr->flags &= ~WM_ADDED_TOPLEVEL_COLORMAP;
  1251.     }
  1252.     wmPtr->flags |= WM_COLORMAPS_EXPLICIT;
  1253.     if (wmPtr->cmapList != NULL) {
  1254.         ckfree((char *)wmPtr->cmapList);
  1255.     }
  1256.     wmPtr->cmapList = cmapList;
  1257.     wmPtr->cmapCount = windowArgc;
  1258.     ckfree((char *) windowArgv);
  1259.  
  1260.     /*
  1261.      * Now we need to force the updated colormaps to be installed.
  1262.      */
  1263.  
  1264.     if (wmPtr == foregroundWmPtr) {
  1265.         InstallColormaps(wmPtr->wrapper, WM_QUERYNEWPALETTE, 1);
  1266.     } else {
  1267.         InstallColormaps(wmPtr->wrapper, WM_PALETTECHANGED, 0);
  1268.     }
  1269.     return TCL_OK;
  1270.     } else if ((c == 'c') && (strncmp(argv[1], "command", length) == 0)
  1271.         && (length >= 3)) {
  1272.     int cmdArgc;
  1273.     char **cmdArgv;
  1274.  
  1275.     if ((argc != 3) && (argc != 4)) {
  1276.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1277.             argv[0], " command window ?value?\"",
  1278.             (char *) NULL);
  1279.         return TCL_ERROR;
  1280.     }
  1281.     if (argc == 3) {
  1282.         if (wmPtr->cmdArgv != NULL) {
  1283.         interp->result = Tcl_Merge(wmPtr->cmdArgc, wmPtr->cmdArgv);
  1284.         interp->freeProc = TCL_DYNAMIC;
  1285.         }
  1286.         return TCL_OK;
  1287.     }
  1288.     if (argv[3][0] == 0) {
  1289.         if (wmPtr->cmdArgv != NULL) {
  1290.         ckfree((char *) wmPtr->cmdArgv);
  1291.         wmPtr->cmdArgv = NULL;
  1292.         if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  1293.             XDeleteProperty(winPtr->display, winPtr->window,
  1294.                 Tk_InternAtom((Tk_Window) winPtr, "WM_COMMAND"));
  1295.         }
  1296.         }
  1297.         return TCL_OK;
  1298.     }
  1299.     if (Tcl_SplitList(interp, argv[3], &cmdArgc, &cmdArgv) != TCL_OK) {
  1300.         return TCL_ERROR;
  1301.     }
  1302.     if (wmPtr->cmdArgv != NULL) {
  1303.         ckfree((char *) wmPtr->cmdArgv);
  1304.     }
  1305.     wmPtr->cmdArgc = cmdArgc;
  1306.     wmPtr->cmdArgv = cmdArgv;
  1307.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  1308.         XSetCommand(winPtr->display, winPtr->window, cmdArgv, cmdArgc);
  1309.     }
  1310.     } else if ((c == 'd') && (strncmp(argv[1], "deiconify", length) == 0)) {
  1311.     if (argc != 3) {
  1312.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1313.             argv[0], " deiconify window\"", (char *) NULL);
  1314.         return TCL_ERROR;
  1315.     }
  1316.     if (wmPtr->iconFor != NULL) {
  1317.         Tcl_AppendResult(interp, "can't deiconify ", argv[2],
  1318.             ": it is an icon for ", winPtr->pathName, (char *) NULL);
  1319.         return TCL_ERROR;
  1320.     }
  1321.         if (winPtr->flags & TK_EMBEDDED) {
  1322.             Tcl_AppendResult(interp, "can't deiconify ", winPtr->pathName,
  1323.                     ": it is an embedded window", (char *) NULL);
  1324.             return TCL_ERROR;
  1325.         }
  1326.     TkpWmSetState(winPtr, NormalState);
  1327.     } else if ((c == 'f') && (strncmp(argv[1], "focusmodel", length) == 0)
  1328.         && (length >= 2)) {
  1329.     if ((argc != 3) && (argc != 4)) {
  1330.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1331.             argv[0], " focusmodel window ?active|passive?\"",
  1332.             (char *) NULL);
  1333.         return TCL_ERROR;
  1334.     }
  1335.     if (argc == 3) {
  1336.         interp->result = wmPtr->hints.input ? "passive" : "active";
  1337.         return TCL_OK;
  1338.     }
  1339.     c = argv[3][0];
  1340.     length = strlen(argv[3]);
  1341.     if ((c == 'a') && (strncmp(argv[3], "active", length) == 0)) {
  1342.         wmPtr->hints.input = False;
  1343.     } else if ((c == 'p') && (strncmp(argv[3], "passive", length) == 0)) {
  1344.         wmPtr->hints.input = True;
  1345.     } else {
  1346.         Tcl_AppendResult(interp, "bad argument \"", argv[3],
  1347.             "\": must be active or passive", (char *) NULL);
  1348.         return TCL_ERROR;
  1349.     }
  1350.     } else if ((c == 'f') && (strncmp(argv[1], "frame", length) == 0)
  1351.         && (length >= 2)) {
  1352.     HWND hwnd;
  1353.  
  1354.     if (argc != 3) {
  1355.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1356.             argv[0], " frame window\"", (char *) NULL);
  1357.         return TCL_ERROR;
  1358.     }
  1359.     hwnd = wmPtr->wrapper;
  1360.     if (hwnd == NULL) {
  1361.         hwnd = Tk_GetHWND(Tk_WindowId((Tk_Window) winPtr));
  1362.     }
  1363.     sprintf(interp->result, "0x%x", (unsigned int) hwnd);
  1364.     } else if ((c == 'g') && (strncmp(argv[1], "geometry", length) == 0)
  1365.         && (length >= 2)) {
  1366.     char xSign, ySign;
  1367.     int width, height;
  1368.  
  1369.     if ((argc != 3) && (argc != 4)) {
  1370.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1371.             argv[0], " geometry window ?newGeometry?\"",
  1372.             (char *) NULL);
  1373.         return TCL_ERROR;
  1374.     }
  1375.     if (argc == 3) {
  1376.         xSign = (wmPtr->flags & WM_NEGATIVE_X) ? '-' : '+';
  1377.         ySign = (wmPtr->flags & WM_NEGATIVE_Y) ? '-' : '+';
  1378.         if (wmPtr->gridWin != NULL) {
  1379.         width = wmPtr->reqGridWidth + (winPtr->changes.width
  1380.             - winPtr->reqWidth)/wmPtr->widthInc;
  1381.         height = wmPtr->reqGridHeight + (winPtr->changes.height
  1382.             - winPtr->reqHeight)/wmPtr->heightInc;
  1383.         } else {
  1384.         width = winPtr->changes.width;
  1385.         height = winPtr->changes.height;
  1386.         }
  1387.         sprintf(interp->result, "%dx%d%c%d%c%d", width, height,
  1388.             xSign, wmPtr->x, ySign, wmPtr->y);
  1389.         return TCL_OK;
  1390.     }
  1391.     if (*argv[3] == '\0') {
  1392.         wmPtr->width = -1;
  1393.         wmPtr->height = -1;
  1394.         goto updateGeom;
  1395.     }
  1396.     return ParseGeometry(interp, argv[3], winPtr);
  1397.     } else if ((c == 'g') && (strncmp(argv[1], "grid", length) == 0)
  1398.         && (length >= 3)) {
  1399.     int reqWidth, reqHeight, widthInc, heightInc;
  1400.  
  1401.     if ((argc != 3) && (argc != 7)) {
  1402.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1403.             argv[0], " grid window ?baseWidth baseHeight ",
  1404.             "widthInc heightInc?\"", (char *) NULL);
  1405.         return TCL_ERROR;
  1406.     }
  1407.     if (argc == 3) {
  1408.         if (wmPtr->sizeHintsFlags & PBaseSize) {
  1409.         sprintf(interp->result, "%d %d %d %d", wmPtr->reqGridWidth,
  1410.             wmPtr->reqGridHeight, wmPtr->widthInc,
  1411.             wmPtr->heightInc);
  1412.         }
  1413.         return TCL_OK;
  1414.     }
  1415.     if (*argv[3] == '\0') {
  1416.         /*
  1417.          * Turn off gridding and reset the width and height
  1418.          * to make sense as ungridded numbers.
  1419.          */
  1420.  
  1421.         wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
  1422.         if (wmPtr->width != -1) {
  1423.         wmPtr->width = winPtr->reqWidth + (wmPtr->width
  1424.             - wmPtr->reqGridWidth)*wmPtr->widthInc;
  1425.         wmPtr->height = winPtr->reqHeight + (wmPtr->height
  1426.             - wmPtr->reqGridHeight)*wmPtr->heightInc;
  1427.         }
  1428.         wmPtr->widthInc = 1;
  1429.         wmPtr->heightInc = 1;
  1430.     } else {
  1431.         if ((Tcl_GetInt(interp, argv[3], &reqWidth) != TCL_OK)
  1432.             || (Tcl_GetInt(interp, argv[4], &reqHeight) != TCL_OK)
  1433.             || (Tcl_GetInt(interp, argv[5], &widthInc) != TCL_OK)
  1434.             || (Tcl_GetInt(interp, argv[6], &heightInc) != TCL_OK)) {
  1435.         return TCL_ERROR;
  1436.         }
  1437.         if (reqWidth < 0) {
  1438.         interp->result = "baseWidth can't be < 0";
  1439.         return TCL_ERROR;
  1440.         }
  1441.         if (reqHeight < 0) {
  1442.         interp->result = "baseHeight can't be < 0";
  1443.         return TCL_ERROR;
  1444.         }
  1445.         if (widthInc < 0) {
  1446.         interp->result = "widthInc can't be < 0";
  1447.         return TCL_ERROR;
  1448.         }
  1449.         if (heightInc < 0) {
  1450.         interp->result = "heightInc can't be < 0";
  1451.         return TCL_ERROR;
  1452.         }
  1453.         Tk_SetGrid((Tk_Window) winPtr, reqWidth, reqHeight, widthInc,
  1454.             heightInc);
  1455.     }
  1456.     goto updateGeom;
  1457.     } else if ((c == 'g') && (strncmp(argv[1], "group", length) == 0)
  1458.         && (length >= 3)) {
  1459.     Tk_Window tkwin2;
  1460.  
  1461.     if ((argc != 3) && (argc != 4)) {
  1462.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1463.             argv[0], " group window ?pathName?\"",
  1464.             (char *) NULL);
  1465.         return TCL_ERROR;
  1466.     }
  1467.     if (argc == 3) {
  1468.         if (wmPtr->hints.flags & WindowGroupHint) {
  1469.         interp->result = wmPtr->leaderName;
  1470.         }
  1471.         return TCL_OK;
  1472.     }
  1473.     if (*argv[3] == '\0') {
  1474.         wmPtr->hints.flags &= ~WindowGroupHint;
  1475.         if (wmPtr->leaderName != NULL) {
  1476.         ckfree(wmPtr->leaderName);
  1477.         }
  1478.         wmPtr->leaderName = NULL;
  1479.     } else {
  1480.         tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
  1481.         if (tkwin2 == NULL) {
  1482.         return TCL_ERROR;
  1483.         }
  1484.         Tk_MakeWindowExist(tkwin2);
  1485.         wmPtr->hints.window_group = Tk_WindowId(tkwin2);
  1486.         wmPtr->hints.flags |= WindowGroupHint;
  1487.         wmPtr->leaderName = ckalloc((unsigned) (strlen(argv[3])+1));
  1488.         strcpy(wmPtr->leaderName, argv[3]);
  1489.     }
  1490.     } else if ((c == 'i') && (strncmp(argv[1], "iconbitmap", length) == 0)
  1491.         && (length >= 5)) {
  1492.     Pixmap pixmap;
  1493.  
  1494.     if ((argc != 3) && (argc != 4)) {
  1495.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1496.             argv[0], " iconbitmap window ?bitmap?\"",
  1497.             (char *) NULL);
  1498.         return TCL_ERROR;
  1499.     }
  1500.     if (argc == 3) {
  1501.         if (wmPtr->hints.flags & IconPixmapHint) {
  1502.         interp->result = Tk_NameOfBitmap(winPtr->display,
  1503.             wmPtr->hints.icon_pixmap);
  1504.         }
  1505.         return TCL_OK;
  1506.     }
  1507.     if (*argv[3] == '\0') {
  1508.         if (wmPtr->hints.icon_pixmap != None) {
  1509.         Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_pixmap);
  1510.         }
  1511.         wmPtr->hints.flags &= ~IconPixmapHint;
  1512.     } else {
  1513.         pixmap = Tk_GetBitmap(interp, (Tk_Window) winPtr,
  1514.             Tk_GetUid(argv[3]));
  1515.         if (pixmap == None) {
  1516.         return TCL_ERROR;
  1517.         }
  1518.         wmPtr->hints.icon_pixmap = pixmap;
  1519.         wmPtr->hints.flags |= IconPixmapHint;
  1520.     }
  1521.     } else if ((c == 'i') && (strncmp(argv[1], "iconify", length) == 0)
  1522.         && (length >= 5)) {
  1523.     if (argc != 3) {
  1524.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1525.             argv[0], " iconify window\"", (char *) NULL);
  1526.         return TCL_ERROR;
  1527.     }
  1528.     if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
  1529.         Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
  1530.             "\": override-redirect flag is set", (char *) NULL);
  1531.         return TCL_ERROR;
  1532.     }
  1533.     if (wmPtr->masterPtr != NULL) {
  1534.         Tcl_AppendResult(interp, "can't iconify \"", winPtr->pathName,
  1535.             "\": it is a transient", (char *) NULL);
  1536.         return TCL_ERROR;
  1537.     }
  1538.     if (wmPtr->iconFor != NULL) {
  1539.         Tcl_AppendResult(interp, "can't iconify ", argv[2],
  1540.             ": it is an icon for ", winPtr->pathName, (char *) NULL);
  1541.         return TCL_ERROR;
  1542.     }
  1543.         if (winPtr->flags & TK_EMBEDDED) {
  1544.             Tcl_AppendResult(interp, "can't iconify ", winPtr->pathName,
  1545.                     ": it is an embedded window", (char *) NULL);
  1546.             return TCL_ERROR;
  1547.         }
  1548.     TkpWmSetState(winPtr, IconicState);
  1549.     } else if ((c == 'i') && (strncmp(argv[1], "iconmask", length) == 0)
  1550.         && (length >= 5)) {
  1551.     Pixmap pixmap;
  1552.  
  1553.     if ((argc != 3) && (argc != 4)) {
  1554.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1555.             argv[0], " iconmask window ?bitmap?\"",
  1556.             (char *) NULL);
  1557.         return TCL_ERROR;
  1558.     }
  1559.     if (argc == 3) {
  1560.         if (wmPtr->hints.flags & IconMaskHint) {
  1561.         interp->result = Tk_NameOfBitmap(winPtr->display,
  1562.             wmPtr->hints.icon_mask);
  1563.         }
  1564.         return TCL_OK;
  1565.     }
  1566.     if (*argv[3] == '\0') {
  1567.         if (wmPtr->hints.icon_mask != None) {
  1568.         Tk_FreeBitmap(winPtr->display, wmPtr->hints.icon_mask);
  1569.         }
  1570.         wmPtr->hints.flags &= ~IconMaskHint;
  1571.     } else {
  1572.         pixmap = Tk_GetBitmap(interp, tkwin, Tk_GetUid(argv[3]));
  1573.         if (pixmap == None) {
  1574.         return TCL_ERROR;
  1575.         }
  1576.         wmPtr->hints.icon_mask = pixmap;
  1577.         wmPtr->hints.flags |= IconMaskHint;
  1578.     }
  1579.     } else if ((c == 'i') && (strncmp(argv[1], "iconname", length) == 0)
  1580.         && (length >= 5)) {
  1581.     if (argc > 4) {
  1582.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1583.             argv[0], " iconname window ?newName?\"", (char *) NULL);
  1584.         return TCL_ERROR;
  1585.     }
  1586.     if (argc == 3) {
  1587.         interp->result = (wmPtr->iconName != NULL) ? wmPtr->iconName : "";
  1588.         return TCL_OK;
  1589.     } else {
  1590.         wmPtr->iconName = Tk_GetUid(argv[3]);
  1591.         if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  1592.         XSetIconName(winPtr->display, winPtr->window, wmPtr->iconName);
  1593.         }
  1594.     }
  1595.     } else if ((c == 'i') && (strncmp(argv[1], "iconposition", length) == 0)
  1596.         && (length >= 5)) {
  1597.     int x, y;
  1598.  
  1599.     if ((argc != 3) && (argc != 5)) {
  1600.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1601.             argv[0], " iconposition window ?x y?\"",
  1602.             (char *) NULL);
  1603.         return TCL_ERROR;
  1604.     }
  1605.     if (argc == 3) {
  1606.         if (wmPtr->hints.flags & IconPositionHint) {
  1607.         sprintf(interp->result, "%d %d", wmPtr->hints.icon_x,
  1608.             wmPtr->hints.icon_y);
  1609.         }
  1610.         return TCL_OK;
  1611.     }
  1612.     if (*argv[3] == '\0') {
  1613.         wmPtr->hints.flags &= ~IconPositionHint;
  1614.     } else {
  1615.         if ((Tcl_GetInt(interp, argv[3], &x) != TCL_OK)
  1616.             || (Tcl_GetInt(interp, argv[4], &y) != TCL_OK)){
  1617.         return TCL_ERROR;
  1618.         }
  1619.         wmPtr->hints.icon_x = x;
  1620.         wmPtr->hints.icon_y = y;
  1621.         wmPtr->hints.flags |= IconPositionHint;
  1622.     }
  1623.     } else if ((c == 'i') && (strncmp(argv[1], "iconwindow", length) == 0)
  1624.         && (length >= 5)) {
  1625.     Tk_Window tkwin2;
  1626.     WmInfo *wmPtr2;
  1627.     XSetWindowAttributes atts;
  1628.  
  1629.     if ((argc != 3) && (argc != 4)) {
  1630.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1631.             argv[0], " iconwindow window ?pathName?\"",
  1632.             (char *) NULL);
  1633.         return TCL_ERROR;
  1634.     }
  1635.     if (argc == 3) {
  1636.         if (wmPtr->icon != NULL) {
  1637.         interp->result = Tk_PathName(wmPtr->icon);
  1638.         }
  1639.         return TCL_OK;
  1640.     }
  1641.     if (*argv[3] == '\0') {
  1642.         wmPtr->hints.flags &= ~IconWindowHint;
  1643.         if (wmPtr->icon != NULL) {
  1644.         /*
  1645.          * Let the window use button events again, then remove
  1646.          * it as icon window.
  1647.          */
  1648.  
  1649.         atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
  1650.             | ButtonPressMask;
  1651.         Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
  1652.         wmPtr2 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  1653.         wmPtr2->iconFor = NULL;
  1654.         wmPtr2->hints.initial_state = WithdrawnState;
  1655.         }
  1656.         wmPtr->icon = NULL;
  1657.     } else {
  1658.         tkwin2 = Tk_NameToWindow(interp, argv[3], tkwin);
  1659.         if (tkwin2 == NULL) {
  1660.         return TCL_ERROR;
  1661.         }
  1662.         if (!Tk_IsTopLevel(tkwin2)) {
  1663.         Tcl_AppendResult(interp, "can't use ", argv[3],
  1664.             " as icon window: not at top level", (char *) NULL);
  1665.         return TCL_ERROR;
  1666.         }
  1667.         wmPtr2 = ((TkWindow *) tkwin2)->wmInfoPtr;
  1668.         if (wmPtr2->iconFor != NULL) {
  1669.         Tcl_AppendResult(interp, argv[3], " is already an icon for ",
  1670.             Tk_PathName(wmPtr2->iconFor), (char *) NULL);
  1671.         return TCL_ERROR;
  1672.         }
  1673.         if (wmPtr->icon != NULL) {
  1674.         WmInfo *wmPtr3 = ((TkWindow *) wmPtr->icon)->wmInfoPtr;
  1675.         wmPtr3->iconFor = NULL;
  1676.  
  1677.         /*
  1678.          * Let the window use button events again.
  1679.          */
  1680.  
  1681.         atts.event_mask = Tk_Attributes(wmPtr->icon)->event_mask
  1682.             | ButtonPressMask;
  1683.         Tk_ChangeWindowAttributes(wmPtr->icon, CWEventMask, &atts);
  1684.         }
  1685.  
  1686.         /*
  1687.          * Disable button events in the icon window:  some window
  1688.          * managers (like olvwm) want to get the events themselves,
  1689.          * but X only allows one application at a time to receive
  1690.          * button events for a window.
  1691.          */
  1692.  
  1693.         atts.event_mask = Tk_Attributes(tkwin2)->event_mask
  1694.             & ~ButtonPressMask;
  1695.         Tk_ChangeWindowAttributes(tkwin2, CWEventMask, &atts);
  1696.         Tk_MakeWindowExist(tkwin2);
  1697.         wmPtr->hints.icon_window = Tk_WindowId(tkwin2);
  1698.         wmPtr->hints.flags |= IconWindowHint;
  1699.         wmPtr->icon = tkwin2;
  1700.         wmPtr2->iconFor = (Tk_Window) winPtr;
  1701.         if (!(wmPtr2->flags & WM_NEVER_MAPPED)) {
  1702.         if (XWithdrawWindow(Tk_Display(tkwin2), Tk_WindowId(tkwin2),
  1703.             Tk_ScreenNumber(tkwin2)) == 0) {
  1704.             interp->result =
  1705.                 "couldn't send withdraw message to window manager";
  1706.             return TCL_ERROR;
  1707.         }
  1708.         }
  1709.     }
  1710.     } else if ((c == 'm') && (strncmp(argv[1], "maxsize", length) == 0)
  1711.         && (length >= 2)) {
  1712.     int width, height;
  1713.     if ((argc != 3) && (argc != 5)) {
  1714.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1715.             argv[0], " maxsize window ?width height?\"",
  1716.                     (char *) NULL);
  1717.         return TCL_ERROR;
  1718.     }
  1719.     if (argc == 3) {
  1720.         GetMaxSize(wmPtr, &width, &height);
  1721.         sprintf(interp->result, "%d %d", width, height);
  1722.         return TCL_OK;
  1723.     }
  1724.     if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
  1725.         || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
  1726.         return TCL_ERROR;
  1727.     }
  1728.     wmPtr->maxWidth = width;
  1729.     wmPtr->maxHeight = height;
  1730.     goto updateGeom;
  1731.     } else if ((c == 'm') && (strncmp(argv[1], "minsize", length) == 0)
  1732.         && (length >= 2)) {
  1733.     int width, height;
  1734.     if ((argc != 3) && (argc != 5)) {
  1735.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1736.             argv[0], " minsize window ?width height?\"",
  1737.                     (char *) NULL);
  1738.         return TCL_ERROR;
  1739.     }
  1740.     if (argc == 3) {
  1741.         GetMinSize(wmPtr, &width, &height);
  1742.         sprintf(interp->result, "%d %d", width, height);
  1743.         return TCL_OK;
  1744.     }
  1745.     if ((Tcl_GetInt(interp, argv[3], &width) != TCL_OK)
  1746.         || (Tcl_GetInt(interp, argv[4], &height) != TCL_OK)) {
  1747.         return TCL_ERROR;
  1748.     }
  1749.     wmPtr->minWidth = width;
  1750.     wmPtr->minHeight = height;
  1751.     goto updateGeom;
  1752.     } else if ((c == 'o')
  1753.         && (strncmp(argv[1], "overrideredirect", length) == 0)) {
  1754.     int boolean;
  1755.     XSetWindowAttributes atts;
  1756.  
  1757.     if ((argc != 3) && (argc != 4)) {
  1758.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1759.             argv[0], " overrideredirect window ?boolean?\"",
  1760.             (char *) NULL);
  1761.         return TCL_ERROR;
  1762.     }
  1763.     if (argc == 3) {
  1764.         if (Tk_Attributes((Tk_Window) winPtr)->override_redirect) {
  1765.         interp->result = "1";
  1766.         } else {
  1767.         interp->result = "0";
  1768.         }
  1769.         return TCL_OK;
  1770.     }
  1771.     if (Tcl_GetBoolean(interp, argv[3], &boolean) != TCL_OK) {
  1772.         return TCL_ERROR;
  1773.     }
  1774.     atts.override_redirect = (boolean) ? True : False;
  1775.     Tk_ChangeWindowAttributes((Tk_Window) winPtr, CWOverrideRedirect,
  1776.         &atts);
  1777.     if (!(wmPtr->flags & (WM_NEVER_MAPPED)
  1778.         && !(winPtr->flags & TK_EMBEDDED))) {
  1779.         UpdateWrapper(winPtr);
  1780.     }
  1781.     } else if ((c == 'p') && (strncmp(argv[1], "positionfrom", length) == 0)
  1782.         && (length >= 2)) {
  1783.     if ((argc != 3) && (argc != 4)) {
  1784.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1785.             argv[0], " positionfrom window ?user/program?\"",
  1786.             (char *) NULL);
  1787.         return TCL_ERROR;
  1788.     }
  1789.     if (argc == 3) {
  1790.         if (wmPtr->sizeHintsFlags & USPosition) {
  1791.         interp->result = "user";
  1792.         } else if (wmPtr->sizeHintsFlags & PPosition) {
  1793.         interp->result = "program";
  1794.         }
  1795.         return TCL_OK;
  1796.     }
  1797.     if (*argv[3] == '\0') {
  1798.         wmPtr->sizeHintsFlags &= ~(USPosition|PPosition);
  1799.     } else {
  1800.         c = argv[3][0];
  1801.         length = strlen(argv[3]);
  1802.         if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
  1803.         wmPtr->sizeHintsFlags &= ~PPosition;
  1804.         wmPtr->sizeHintsFlags |= USPosition;
  1805.         } else if ((c == 'p')
  1806.                     && (strncmp(argv[3], "program", length) == 0)) {
  1807.         wmPtr->sizeHintsFlags &= ~USPosition;
  1808.         wmPtr->sizeHintsFlags |= PPosition;
  1809.         } else {
  1810.         Tcl_AppendResult(interp, "bad argument \"", argv[3],
  1811.             "\": must be program or user", (char *) NULL);
  1812.         return TCL_ERROR;
  1813.         }
  1814.     }
  1815.     goto updateGeom;
  1816.     } else if ((c == 'p') && (strncmp(argv[1], "protocol", length) == 0)
  1817.         && (length >= 2)) {
  1818.     register ProtocolHandler *protPtr, *prevPtr;
  1819.     Atom protocol;
  1820.     int cmdLength;
  1821.  
  1822.     if ((argc < 3) || (argc > 5)) {
  1823.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1824.             argv[0], " protocol window ?name? ?command?\"",
  1825.             (char *) NULL);
  1826.         return TCL_ERROR;
  1827.     }
  1828.     if (argc == 3) {
  1829.         /*
  1830.          * Return a list of all defined protocols for the window.
  1831.          */
  1832.         for (protPtr = wmPtr->protPtr; protPtr != NULL;
  1833.             protPtr = protPtr->nextPtr) {
  1834.         Tcl_AppendElement(interp,
  1835.             Tk_GetAtomName((Tk_Window) winPtr, protPtr->protocol));
  1836.         }
  1837.         return TCL_OK;
  1838.     }
  1839.     protocol = Tk_InternAtom((Tk_Window) winPtr, argv[3]);
  1840.     if (argc == 4) {
  1841.         /*
  1842.          * Return the command to handle a given protocol.
  1843.          */
  1844.         for (protPtr = wmPtr->protPtr; protPtr != NULL;
  1845.             protPtr = protPtr->nextPtr) {
  1846.         if (protPtr->protocol == protocol) {
  1847.             interp->result = protPtr->command;
  1848.             return TCL_OK;
  1849.         }
  1850.         }
  1851.         return TCL_OK;
  1852.     }
  1853.  
  1854.     /*
  1855.      * Delete any current protocol handler, then create a new
  1856.      * one with the specified command, unless the command is
  1857.      * empty.
  1858.      */
  1859.  
  1860.     for (protPtr = wmPtr->protPtr, prevPtr = NULL; protPtr != NULL;
  1861.         prevPtr = protPtr, protPtr = protPtr->nextPtr) {
  1862.         if (protPtr->protocol == protocol) {
  1863.         if (prevPtr == NULL) {
  1864.             wmPtr->protPtr = protPtr->nextPtr;
  1865.         } else {
  1866.             prevPtr->nextPtr = protPtr->nextPtr;
  1867.         }
  1868.         Tcl_EventuallyFree((ClientData) protPtr, TCL_DYNAMIC);
  1869.         break;
  1870.         }
  1871.     }
  1872.     cmdLength = strlen(argv[4]);
  1873.     if (cmdLength > 0) {
  1874.         protPtr = (ProtocolHandler *) ckalloc(HANDLER_SIZE(cmdLength));
  1875.         protPtr->protocol = protocol;
  1876.         protPtr->nextPtr = wmPtr->protPtr;
  1877.         wmPtr->protPtr = protPtr;
  1878.         protPtr->interp = interp;
  1879.         strcpy(protPtr->command, argv[4]);
  1880.     }
  1881.     } else if ((c == 'r') && (strncmp(argv[1], "resizable", length) == 0)) {
  1882.     int width, height;
  1883.  
  1884.     if ((argc != 3) && (argc != 5)) {
  1885.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1886.             argv[0], " resizable window ?width height?\"",
  1887.             (char *) NULL);
  1888.         return TCL_ERROR;
  1889.     }
  1890.     if (argc == 3) {
  1891.         sprintf(interp->result, "%d %d",
  1892.             (wmPtr->flags  & WM_WIDTH_NOT_RESIZABLE) ? 0 : 1,
  1893.             (wmPtr->flags  & WM_HEIGHT_NOT_RESIZABLE) ? 0 : 1);
  1894.         return TCL_OK;
  1895.     }
  1896.     if ((Tcl_GetBoolean(interp, argv[3], &width) != TCL_OK)
  1897.         || (Tcl_GetBoolean(interp, argv[4], &height) != TCL_OK)) {
  1898.         return TCL_ERROR;
  1899.     }
  1900.     if (width) {
  1901.         wmPtr->flags &= ~WM_WIDTH_NOT_RESIZABLE;
  1902.     } else {
  1903.         wmPtr->flags |= WM_WIDTH_NOT_RESIZABLE;
  1904.     }
  1905.     if (height) {
  1906.         wmPtr->flags &= ~WM_HEIGHT_NOT_RESIZABLE;
  1907.     } else {
  1908.         wmPtr->flags |= WM_HEIGHT_NOT_RESIZABLE;
  1909.     }
  1910.     wmPtr->flags |= WM_UPDATE_SIZE_HINTS;
  1911.     goto updateGeom;
  1912.     } else if ((c == 's') && (strncmp(argv[1], "sizefrom", length) == 0)
  1913.         && (length >= 2)) {
  1914.     if ((argc != 3) && (argc != 4)) {
  1915.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1916.             argv[0], " sizefrom window ?user|program?\"",
  1917.             (char *) NULL);
  1918.         return TCL_ERROR;
  1919.     }
  1920.     if (argc == 3) {
  1921.         if (wmPtr->sizeHintsFlags & USSize) {
  1922.         interp->result = "user";
  1923.         } else if (wmPtr->sizeHintsFlags & PSize) {
  1924.         interp->result = "program";
  1925.         }
  1926.         return TCL_OK;
  1927.     }
  1928.     if (*argv[3] == '\0') {
  1929.         wmPtr->sizeHintsFlags &= ~(USSize|PSize);
  1930.     } else {
  1931.         c = argv[3][0];
  1932.         length = strlen(argv[3]);
  1933.         if ((c == 'u') && (strncmp(argv[3], "user", length) == 0)) {
  1934.         wmPtr->sizeHintsFlags &= ~PSize;
  1935.         wmPtr->sizeHintsFlags |= USSize;
  1936.         } else if ((c == 'p')
  1937.             && (strncmp(argv[3], "program", length) == 0)) {
  1938.         wmPtr->sizeHintsFlags &= ~USSize;
  1939.         wmPtr->sizeHintsFlags |= PSize;
  1940.         } else {
  1941.         Tcl_AppendResult(interp, "bad argument \"", argv[3],
  1942.             "\": must be program or user", (char *) NULL);
  1943.         return TCL_ERROR;
  1944.         }
  1945.     }
  1946.     goto updateGeom;
  1947.     } else if ((c == 's') && (strncmp(argv[1], "state", length) == 0)
  1948.         && (length >= 2)) {
  1949.     if (argc != 3) {
  1950.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1951.             argv[0], " state window\"", (char *) NULL);
  1952.         return TCL_ERROR;
  1953.     }
  1954.     if (wmPtr->iconFor != NULL) {
  1955.         interp->result = "icon";
  1956.     } else {
  1957.         switch (wmPtr->hints.initial_state) {
  1958.         case NormalState:
  1959.             interp->result = "normal";
  1960.             break;
  1961.         case IconicState:
  1962.             interp->result = "iconic";
  1963.             break;
  1964.         case WithdrawnState:
  1965.             interp->result = "withdrawn";
  1966.             break;
  1967.         case ZoomState:
  1968.             interp->result = "zoomed";
  1969.             break;
  1970.         }
  1971.     }
  1972.     } else if ((c == 't') && (strncmp(argv[1], "title", length) == 0)
  1973.         && (length >= 2)) {
  1974.     if (argc > 4) {
  1975.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1976.             argv[0], " title window ?newTitle?\"", (char *) NULL);
  1977.         return TCL_ERROR;
  1978.     }
  1979.     if (argc == 3) {
  1980.         interp->result = (wmPtr->titleUid != NULL) ? wmPtr->titleUid
  1981.             : winPtr->nameUid;
  1982.         return TCL_OK;
  1983.     } else {
  1984.         wmPtr->titleUid = Tk_GetUid(argv[3]);
  1985.         if (!(wmPtr->flags & WM_NEVER_MAPPED) && wmPtr->wrapper != NULL) {
  1986.         SetWindowText(wmPtr->wrapper, wmPtr->titleUid);
  1987.         }
  1988.     }
  1989.     } else if ((c == 't') && (strncmp(argv[1], "transient", length) == 0)
  1990.         && (length >= 3)) {
  1991.     TkWindow *masterPtr;
  1992.  
  1993.     if ((argc != 3) && (argc != 4)) {
  1994.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  1995.             argv[0], " transient window ?master?\"", (char *) NULL);
  1996.         return TCL_ERROR;
  1997.     }
  1998.     if (argc == 3) {
  1999.         if (wmPtr->masterPtr != NULL) {
  2000.         Tcl_SetResult(interp, Tk_PathName(wmPtr->masterPtr),
  2001.             TCL_STATIC);
  2002.         }
  2003.         return TCL_OK;
  2004.     }
  2005.     if (argv[3][0] == '\0') {
  2006.         wmPtr->masterPtr = NULL;
  2007.     } else {
  2008.         masterPtr = (TkWindow*) Tk_NameToWindow(interp, argv[3], tkwin);
  2009.         if (masterPtr == NULL) {
  2010.         return TCL_ERROR;
  2011.         }
  2012.         if (masterPtr == winPtr) {
  2013.         wmPtr->masterPtr = NULL;
  2014.         } else {
  2015.         Tk_MakeWindowExist((Tk_Window)masterPtr);
  2016.  
  2017.         /*
  2018.          * Ensure that the master window is actually a Tk toplevel.
  2019.          */
  2020.  
  2021.         while (!(masterPtr->flags & TK_TOP_LEVEL)) {
  2022.             masterPtr = masterPtr->parentPtr;
  2023.         }
  2024.         wmPtr->masterPtr = masterPtr;
  2025.  
  2026.         /*
  2027.          * Ensure that the transient window is either mapped or 
  2028.          * unmapped like its master.
  2029.          */
  2030.  
  2031.         TkpWmSetState(winPtr, NormalState);
  2032.         }
  2033.     }
  2034.     if (!(wmPtr->flags & (WM_NEVER_MAPPED)
  2035.         && !(winPtr->flags & TK_EMBEDDED))) {
  2036.         UpdateWrapper(winPtr);
  2037.     }
  2038.     } else if ((c == 'w') && (strncmp(argv[1], "withdraw", length) == 0)) {
  2039.     if (argc != 3) {
  2040.         Tcl_AppendResult(interp, "wrong # arguments: must be \"",
  2041.             argv[0], " withdraw window\"", (char *) NULL);
  2042.         return TCL_ERROR;
  2043.     }
  2044.     if (wmPtr->iconFor != NULL) {
  2045.         Tcl_AppendResult(interp, "can't withdraw ", argv[2],
  2046.             ": it is an icon for ", Tk_PathName(wmPtr->iconFor),
  2047.             (char *) NULL);
  2048.         return TCL_ERROR;
  2049.     }
  2050.     TkpWmSetState(winPtr, WithdrawnState);
  2051.     } else {
  2052.     Tcl_AppendResult(interp, "unknown or ambiguous option \"", argv[1],
  2053.         "\": must be aspect, client, command, deiconify, ",
  2054.         "focusmodel, frame, geometry, grid, group, iconbitmap, ",
  2055.         "iconify, iconmask, iconname, iconposition, ",
  2056.         "iconwindow, maxsize, minsize, overrideredirect, ",
  2057.         "positionfrom, protocol, resizable, sizefrom, state, title, ",
  2058.         "transient, or withdraw",
  2059.         (char *) NULL);
  2060.     return TCL_ERROR;
  2061.     }
  2062.     return TCL_OK;
  2063.  
  2064.     updateGeom:
  2065.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  2066.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  2067.     wmPtr->flags |= WM_UPDATE_PENDING;
  2068.     }
  2069.     return TCL_OK;
  2070. }
  2071.  
  2072. /*
  2073.  *----------------------------------------------------------------------
  2074.  *
  2075.  * Tk_SetGrid --
  2076.  *
  2077.  *    This procedure is invoked by a widget when it wishes to set a grid
  2078.  *    coordinate system that controls the size of a top-level window.
  2079.  *    It provides a C interface equivalent to the "wm grid" command and
  2080.  *    is usually asscoiated with the -setgrid option.
  2081.  *
  2082.  * Results:
  2083.  *    None.
  2084.  *
  2085.  * Side effects:
  2086.  *    Grid-related information will be passed to the window manager, so
  2087.  *    that the top-level window associated with tkwin will resize on
  2088.  *    even grid units.  If some other window already controls gridding
  2089.  *    for the top-level window then this procedure call has no effect.
  2090.  *
  2091.  *----------------------------------------------------------------------
  2092.  */
  2093.  
  2094. void
  2095. Tk_SetGrid(tkwin, reqWidth, reqHeight, widthInc, heightInc)
  2096.     Tk_Window tkwin;        /* Token for window.  New window mgr info
  2097.                  * will be posted for the top-level window
  2098.                  * associated with this window. */
  2099.     int reqWidth;        /* Width (in grid units) corresponding to
  2100.                  * the requested geometry for tkwin. */
  2101.     int reqHeight;        /* Height (in grid units) corresponding to
  2102.                  * the requested geometry for tkwin. */
  2103.     int widthInc, heightInc;    /* Pixel increments corresponding to a
  2104.                  * change of one grid unit. */
  2105. {
  2106.     TkWindow *winPtr = (TkWindow *) tkwin;
  2107.     register WmInfo *wmPtr;
  2108.  
  2109.     /*
  2110.      * Find the top-level window for tkwin, plus the window manager
  2111.      * information.
  2112.      */
  2113.  
  2114.     while (!(winPtr->flags & TK_TOP_LEVEL)) {
  2115.     winPtr = winPtr->parentPtr;
  2116.     }
  2117.     wmPtr = winPtr->wmInfoPtr;
  2118.  
  2119.     if ((wmPtr->gridWin != NULL) && (wmPtr->gridWin != tkwin)) {
  2120.     return;
  2121.     }
  2122.  
  2123.     if ((wmPtr->reqGridWidth == reqWidth)
  2124.         && (wmPtr->reqGridHeight == reqHeight)
  2125.         && (wmPtr->widthInc == widthInc)
  2126.         && (wmPtr->heightInc == heightInc)
  2127.         && ((wmPtr->sizeHintsFlags & (PBaseSize|PResizeInc))
  2128.             == PBaseSize|PResizeInc)) {
  2129.     return;
  2130.     }
  2131.  
  2132.     /*
  2133.      * If gridding was previously off, then forget about any window
  2134.      * size requests made by the user or via "wm geometry":  these are
  2135.      * in pixel units and there's no easy way to translate them to
  2136.      * grid units since the new requested size of the top-level window in
  2137.      * pixels may not yet have been registered yet (it may filter up
  2138.      * the hierarchy in DoWhenIdle handlers).  However, if the window
  2139.      * has never been mapped yet then just leave the window size alone:
  2140.      * assume that it is intended to be in grid units but just happened
  2141.      * to have been specified before this procedure was called.
  2142.      */
  2143.  
  2144.     if ((wmPtr->gridWin == NULL) && !(wmPtr->flags & WM_NEVER_MAPPED)) {
  2145.     wmPtr->width = -1;
  2146.     wmPtr->height = -1;
  2147.     }
  2148.  
  2149.     /* 
  2150.      * Set the new gridding information, and start the process of passing
  2151.      * all of this information to the window manager.
  2152.      */
  2153.  
  2154.     wmPtr->gridWin = tkwin;
  2155.     wmPtr->reqGridWidth = reqWidth;
  2156.     wmPtr->reqGridHeight = reqHeight;
  2157.     wmPtr->widthInc = widthInc;
  2158.     wmPtr->heightInc = heightInc;
  2159.     wmPtr->sizeHintsFlags |= PBaseSize|PResizeInc;
  2160.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  2161.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  2162.     wmPtr->flags |= WM_UPDATE_PENDING;
  2163.     }
  2164. }
  2165.  
  2166. /*
  2167.  *----------------------------------------------------------------------
  2168.  *
  2169.  * Tk_UnsetGrid --
  2170.  *
  2171.  *    This procedure cancels the effect of a previous call
  2172.  *    to Tk_SetGrid.
  2173.  *
  2174.  * Results:
  2175.  *    None.
  2176.  *
  2177.  * Side effects:
  2178.  *    If tkwin currently controls gridding for its top-level window,
  2179.  *    gridding is cancelled for that top-level window;  if some other
  2180.  *    window controls gridding then this procedure has no effect.
  2181.  *
  2182.  *----------------------------------------------------------------------
  2183.  */
  2184.  
  2185. void
  2186. Tk_UnsetGrid(tkwin)
  2187.     Tk_Window tkwin;        /* Token for window that is currently
  2188.                  * controlling gridding. */
  2189. {
  2190.     TkWindow *winPtr = (TkWindow *) tkwin;
  2191.     register WmInfo *wmPtr;
  2192.  
  2193.     /*
  2194.      * Find the top-level window for tkwin, plus the window manager
  2195.      * information.
  2196.      */
  2197.  
  2198.     while (!(winPtr->flags & TK_TOP_LEVEL)) {
  2199.     winPtr = winPtr->parentPtr;
  2200.     }
  2201.     wmPtr = winPtr->wmInfoPtr;
  2202.     if (tkwin != wmPtr->gridWin) {
  2203.     return;
  2204.     }
  2205.  
  2206.     wmPtr->gridWin = NULL;
  2207.     wmPtr->sizeHintsFlags &= ~(PBaseSize|PResizeInc);
  2208.     if (wmPtr->width != -1) {
  2209.     wmPtr->width = winPtr->reqWidth + (wmPtr->width
  2210.         - wmPtr->reqGridWidth)*wmPtr->widthInc;
  2211.     wmPtr->height = winPtr->reqHeight + (wmPtr->height
  2212.         - wmPtr->reqGridHeight)*wmPtr->heightInc;
  2213.     }
  2214.     wmPtr->widthInc = 1;
  2215.     wmPtr->heightInc = 1;
  2216.  
  2217.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  2218.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  2219.     wmPtr->flags |= WM_UPDATE_PENDING;
  2220.     }
  2221. }
  2222.  
  2223. /*
  2224.  *----------------------------------------------------------------------
  2225.  *
  2226.  * TopLevelEventProc --
  2227.  *
  2228.  *    This procedure is invoked when a top-level (or other externally-
  2229.  *    managed window) is restructured in any way.
  2230.  *
  2231.  * Results:
  2232.  *    None.
  2233.  *
  2234.  * Side effects:
  2235.  *    Tk's internal data structures for the window get modified to
  2236.  *    reflect the structural change.
  2237.  *
  2238.  *----------------------------------------------------------------------
  2239.  */
  2240.  
  2241. static void
  2242. TopLevelEventProc(clientData, eventPtr)
  2243.     ClientData clientData;        /* Window for which event occurred. */
  2244.     XEvent *eventPtr;            /* Event that just happened. */
  2245. {
  2246.     register TkWindow *winPtr = (TkWindow *) clientData;
  2247.  
  2248.     if (eventPtr->type == DestroyNotify) {
  2249.     Tk_ErrorHandler handler;
  2250.  
  2251.     if (!(winPtr->flags & TK_ALREADY_DEAD)) {
  2252.         /*
  2253.          * A top-level window was deleted externally (e.g., by the window
  2254.          * manager).  This is probably not a good thing, but cleanup as
  2255.          * best we can.  The error handler is needed because
  2256.          * Tk_DestroyWindow will try to destroy the window, but of course
  2257.          * it's already gone.
  2258.          */
  2259.     
  2260.         handler = Tk_CreateErrorHandler(winPtr->display, -1, -1, -1,
  2261.             (Tk_ErrorProc *) NULL, (ClientData) NULL);
  2262.         Tk_DestroyWindow((Tk_Window) winPtr);
  2263.         Tk_DeleteErrorHandler(handler);
  2264.     }
  2265.     }
  2266.     else if (eventPtr->type == ConfigureNotify) {
  2267.     WmInfo *wmPtr;
  2268.     wmPtr = winPtr->wmInfoPtr;
  2269.  
  2270.     if (winPtr->flags & TK_EMBEDDED) {
  2271.         Tk_Window tkwin = (Tk_Window)winPtr;
  2272.         SendMessage(wmPtr->wrapper, TK_GEOMETRYREQ, Tk_ReqWidth(tkwin),
  2273.             Tk_ReqHeight(tkwin));
  2274.     }
  2275.     }
  2276. }
  2277.  
  2278. /*
  2279.  *----------------------------------------------------------------------
  2280.  *
  2281.  * TopLevelReqProc --
  2282.  *
  2283.  *    This procedure is invoked by the geometry manager whenever
  2284.  *    the requested size for a top-level window is changed.
  2285.  *
  2286.  * Results:
  2287.  *    None.
  2288.  *
  2289.  * Side effects:
  2290.  *    Arrange for the window to be resized to satisfy the request
  2291.  *    (this happens as a when-idle action).
  2292.  *
  2293.  *----------------------------------------------------------------------
  2294.  */
  2295.  
  2296.     /* ARGSUSED */
  2297. static void
  2298. TopLevelReqProc(dummy, tkwin)
  2299.     ClientData dummy;            /* Not used. */
  2300.     Tk_Window tkwin;            /* Information about window. */
  2301. {
  2302.     TkWindow *winPtr = (TkWindow *) tkwin;
  2303.     WmInfo *wmPtr;
  2304.  
  2305.     wmPtr = winPtr->wmInfoPtr;
  2306.     if (winPtr->flags & TK_EMBEDDED) {
  2307.     SendMessage(wmPtr->wrapper, TK_GEOMETRYREQ, Tk_ReqWidth(tkwin),
  2308.         Tk_ReqHeight(tkwin));
  2309.     }
  2310.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  2311.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  2312.     wmPtr->flags |= WM_UPDATE_PENDING;
  2313.     }
  2314. }
  2315.  
  2316. /*
  2317.  *----------------------------------------------------------------------
  2318.  *
  2319.  * UpdateGeometryInfo --
  2320.  *
  2321.  *    This procedure is invoked when a top-level window is first
  2322.  *    mapped, and also as a when-idle procedure, to bring the
  2323.  *    geometry and/or position of a top-level window back into
  2324.  *    line with what has been requested by the user and/or widgets.
  2325.  *    This procedure doesn't return until the system has
  2326.  *    responded to the geometry change.
  2327.  *
  2328.  * Results:
  2329.  *    None.
  2330.  *
  2331.  * Side effects:
  2332.  *    The window's size and location may change, unless the WM prevents
  2333.  *    that from happening.
  2334.  *
  2335.  *----------------------------------------------------------------------
  2336.  */
  2337.  
  2338. static void
  2339. UpdateGeometryInfo(clientData)
  2340.     ClientData clientData;        /* Pointer to the window's record. */
  2341. {
  2342.     int x, y;            /* Position of border on desktop. */
  2343.     int width, height;        /* Size of client area. */
  2344.     RECT rect;
  2345.     register TkWindow *winPtr = (TkWindow *) clientData;
  2346.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  2347.  
  2348.     wmPtr->flags &= ~WM_UPDATE_PENDING;
  2349.  
  2350.     /*
  2351.      * If the window is minimized or maximized, we should not update
  2352.      * our geometry since it will end up with the wrong values.
  2353.      * ConfigureToplevel will reschedule UpdateGeometryInfo when the
  2354.      * state of the window changes.
  2355.      */
  2356.  
  2357.     if (IsIconic(wmPtr->wrapper) || IsZoomed(wmPtr->wrapper)) {
  2358.     return;
  2359.     }
  2360.  
  2361.     /*
  2362.      * Compute the border size for the current window style.  This
  2363.      * size will include the resize handles, the title bar and the
  2364.      * menubar.  Note that this size will not be correct if the
  2365.      * menubar spans multiple lines.  The height will be off by a
  2366.      * multiple of the menubar height.  It really only measures the
  2367.      * minimum size of the border.
  2368.      */
  2369.  
  2370.     rect.left = rect.right = rect.top = rect.bottom = 0;
  2371.     AdjustWindowRectEx(&rect, wmPtr->style, wmPtr->hMenu != NULL,
  2372.         wmPtr->exStyle);
  2373.     wmPtr->borderWidth = rect.right - rect.left;
  2374.     wmPtr->borderHeight = rect.bottom - rect.top;
  2375.  
  2376.     /*
  2377.      * Compute the new size for the top-level window.  See the
  2378.      * user documentation for details on this, but the size
  2379.      * requested depends on (a) the size requested internally
  2380.      * by the window's widgets, (b) the size requested by the
  2381.      * user in a "wm geometry" command or via wm-based interactive
  2382.      * resizing (if any), and (c) whether or not the window is
  2383.      * gridded.  Don't permit sizes <= 0 because this upsets
  2384.      * the X server.
  2385.      */
  2386.  
  2387.     if (wmPtr->width == -1) {
  2388.     width = winPtr->reqWidth;
  2389.     } else if (wmPtr->gridWin != NULL) {
  2390.     width = winPtr->reqWidth
  2391.         + (wmPtr->width - wmPtr->reqGridWidth)*wmPtr->widthInc;
  2392.     } else {
  2393.     width = wmPtr->width;
  2394.     }
  2395.     if (width <= 0) {
  2396.     width = 1;
  2397.     }
  2398.     if (wmPtr->height == -1) {
  2399.     height = winPtr->reqHeight;
  2400.     } else if (wmPtr->gridWin != NULL) {
  2401.     height = winPtr->reqHeight
  2402.         + (wmPtr->height - wmPtr->reqGridHeight)*wmPtr->heightInc;
  2403.     } else {
  2404.     height = wmPtr->height;
  2405.     }
  2406.     if (height <= 0) {
  2407.     height = 1;
  2408.     }
  2409.  
  2410.     /*
  2411.      * Compute the new position for the upper-left pixel of the window's
  2412.      * decorative frame.  This is tricky, because we need to include the
  2413.      * border widths supplied by a reparented parent in this calculation,
  2414.      * but can't use the parent's current overall size since that may
  2415.      * change as a result of this code.
  2416.      */
  2417.  
  2418.     if (wmPtr->flags & WM_NEGATIVE_X) {
  2419.     x = DisplayWidth(winPtr->display, winPtr->screenNum) - wmPtr->x
  2420.         - (width + wmPtr->borderWidth);
  2421.     } else {
  2422.     x =  wmPtr->x;
  2423.     }
  2424.     if (wmPtr->flags & WM_NEGATIVE_Y) {
  2425.     y = DisplayHeight(winPtr->display, winPtr->screenNum) - wmPtr->y
  2426.         - (height + wmPtr->borderHeight);
  2427.     } else {
  2428.     y =  wmPtr->y;
  2429.     }
  2430.  
  2431.     /*
  2432.      * If this window is embedded and the container is also in this
  2433.      * process, we don't need to do anything special about the
  2434.      * geometry, except to make sure that the desired size is known
  2435.      * by the container.  Also, zero out any position information,
  2436.      * since embedded windows are not allowed to move.
  2437.      */
  2438.  
  2439.     if (winPtr->flags & TK_BOTH_HALVES) {
  2440.     wmPtr->x = wmPtr->y = 0;
  2441.     wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
  2442.     Tk_GeometryRequest((Tk_Window) TkpGetOtherWindow(winPtr),
  2443.         width, height);
  2444.     return;
  2445.     }
  2446.  
  2447.     /*
  2448.      * Reconfigure the window if it isn't already configured correctly.  Base
  2449.      * the size check on what we *asked for* last time, not what we got.
  2450.      * Return immediately if there have been no changes in the requested
  2451.      * geometry of the toplevel.
  2452.      */
  2453.     /* TODO: need to add flag for possible menu size change */
  2454.  
  2455.     if (!((wmPtr->flags & WM_MOVE_PENDING)
  2456.         || (width != wmPtr->configWidth)
  2457.         || (height != wmPtr->configHeight))) {
  2458.     return;
  2459.     }
  2460.     wmPtr->flags &= ~WM_MOVE_PENDING;
  2461.  
  2462.     wmPtr->configWidth = width;
  2463.     wmPtr->configHeight = height;
  2464.         
  2465.     /*
  2466.      * Don't bother moving the window if we are in the process of
  2467.      * creating it.  Just update the geometry info based on what
  2468.      * we asked for.
  2469.      */
  2470.  
  2471.     if (wmPtr->flags & WM_CREATE_PENDING) {
  2472.     winPtr->changes.x = x;
  2473.     winPtr->changes.y = y;
  2474.     winPtr->changes.width = width;
  2475.     winPtr->changes.height = height;
  2476.     return;
  2477.     }
  2478.  
  2479.     wmPtr->flags |= WM_SYNC_PENDING;
  2480.     if (winPtr->flags & TK_EMBEDDED) {
  2481.     /*
  2482.      * The wrapper window is in a different process, so we need
  2483.      * to send it a geometry request.  This protocol assumes that
  2484.      * the other process understands this Tk message, otherwise
  2485.      * our requested geometry will be ignored.
  2486.      */
  2487.  
  2488.     SendMessage(wmPtr->wrapper, TK_GEOMETRYREQ, width, height);
  2489.     } else {
  2490.     int reqHeight, reqWidth;
  2491.     RECT windowRect;
  2492.     int menuInc = GetSystemMetrics(SM_CYMENU);
  2493.     int newHeight;
  2494.  
  2495.     /*
  2496.      * We have to keep resizing the window until we get the
  2497.      * requested height in the client area. If the client
  2498.      * area has zero height, then the window rect is too
  2499.      * small by definition. Try increasing the border height
  2500.      * and try again. Once we have a positive size, then
  2501.      * we can adjust the height exactly. If the window
  2502.      * rect comes back smaller than we requested, we have
  2503.      * hit the maximum constraints that Windows imposes.
  2504.      * Once we find a positive client size, the next size
  2505.      * is the one we try no matter what.
  2506.      */
  2507.  
  2508.     reqHeight = height + wmPtr->borderHeight;
  2509.     reqWidth = width + wmPtr->borderWidth;
  2510.  
  2511.     while (1) {
  2512.         MoveWindow(wmPtr->wrapper, x, y, reqWidth, reqHeight, TRUE);
  2513.         GetWindowRect(wmPtr->wrapper, &windowRect);
  2514.         newHeight = windowRect.bottom - windowRect.top;
  2515.  
  2516.         /*
  2517.          * If the request wasn't satisfied, we have hit an external
  2518.          * constraint and must stop.
  2519.          */
  2520.  
  2521.         if (newHeight < reqHeight) {
  2522.         break;
  2523.         }
  2524.  
  2525.         /*
  2526.          * Now check the size of the client area against our ideal.
  2527.          */
  2528.  
  2529.         GetClientRect(wmPtr->wrapper, &windowRect);
  2530.         newHeight = windowRect.bottom - windowRect.top;
  2531.         
  2532.         if (newHeight == height) {
  2533.         /*
  2534.          * We're done.
  2535.          */
  2536.         break;
  2537.         } else if (newHeight > height) {
  2538.         /*
  2539.          * One last resize to get rid of the extra space.
  2540.          */
  2541.         menuInc = newHeight - height;
  2542.         reqHeight -= menuInc;
  2543.         if (wmPtr->flags & WM_NEGATIVE_Y) {
  2544.             y += menuInc;
  2545.         }
  2546.         MoveWindow(wmPtr->wrapper, x, y, reqWidth, reqHeight, TRUE);
  2547.         break;
  2548.         }
  2549.  
  2550.         /*
  2551.          * We didn't get enough space to satisfy our requested
  2552.          * height, so the menu must have wrapped.  Increase the
  2553.          * size of the window by one menu height and move the
  2554.          * window if it is positioned relative to the lower right
  2555.          * corner of the screen.
  2556.          */
  2557.  
  2558.         reqHeight += menuInc;
  2559.         if (wmPtr->flags & WM_NEGATIVE_Y) {
  2560.         y -= menuInc;
  2561.         }
  2562.     }
  2563.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  2564.         DrawMenuBar(wmPtr->wrapper);
  2565.     }
  2566.     }
  2567.     wmPtr->flags &= ~WM_SYNC_PENDING;
  2568. }
  2569.  
  2570. /*
  2571.  *--------------------------------------------------------------
  2572.  *
  2573.  * ParseGeometry --
  2574.  *
  2575.  *    This procedure parses a geometry string and updates
  2576.  *    information used to control the geometry of a top-level
  2577.  *    window.
  2578.  *
  2579.  * Results:
  2580.  *    A standard Tcl return value, plus an error message in
  2581.  *    interp->result if an error occurs.
  2582.  *
  2583.  * Side effects:
  2584.  *    The size and/or location of winPtr may change.
  2585.  *
  2586.  *--------------------------------------------------------------
  2587.  */
  2588.  
  2589. static int
  2590. ParseGeometry(interp, string, winPtr)
  2591.     Tcl_Interp *interp;        /* Used for error reporting. */
  2592.     char *string;        /* String containing new geometry.  Has the
  2593.                  * standard form "=wxh+x+y". */
  2594.     TkWindow *winPtr;        /* Pointer to top-level window whose
  2595.                  * geometry is to be changed. */
  2596. {
  2597.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  2598.     int x, y, width, height, flags;
  2599.     char *end;
  2600.     register char *p = string;
  2601.  
  2602.     /*
  2603.      * The leading "=" is optional.
  2604.      */
  2605.  
  2606.     if (*p == '=') {
  2607.     p++;
  2608.     }
  2609.  
  2610.     /*
  2611.      * Parse the width and height, if they are present.  Don't
  2612.      * actually update any of the fields of wmPtr until we've
  2613.      * successfully parsed the entire geometry string.
  2614.      */
  2615.  
  2616.     width = wmPtr->width;
  2617.     height = wmPtr->height;
  2618.     x = wmPtr->x;
  2619.     y = wmPtr->y;
  2620.     flags = wmPtr->flags;
  2621.     if (isdigit(UCHAR(*p))) {
  2622.     width = strtoul(p, &end, 10);
  2623.     p = end;
  2624.     if (*p != 'x') {
  2625.         goto error;
  2626.     }
  2627.     p++;
  2628.     if (!isdigit(UCHAR(*p))) {
  2629.         goto error;
  2630.     }
  2631.     height = strtoul(p, &end, 10);
  2632.     p = end;
  2633.     }
  2634.  
  2635.     /*
  2636.      * Parse the X and Y coordinates, if they are present.
  2637.      */
  2638.  
  2639.     if (*p != '\0') {
  2640.     flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
  2641.     if (*p == '-') {
  2642.         flags |= WM_NEGATIVE_X;
  2643.     } else if (*p != '+') {
  2644.         goto error;
  2645.     }
  2646.     p++;
  2647.     if (!isdigit(UCHAR(*p)) && (*p != '-')) {
  2648.         goto error;
  2649.     }
  2650.     x = strtol(p, &end, 10);
  2651.     p = end;
  2652.     if (*p == '-') {
  2653.         flags |= WM_NEGATIVE_Y;
  2654.     } else if (*p != '+') {
  2655.         goto error;
  2656.     }
  2657.     p++;
  2658.     if (!isdigit(UCHAR(*p)) && (*p != '-')) {
  2659.         goto error;
  2660.     }
  2661.     y = strtol(p, &end, 10);
  2662.     if (*end != '\0') {
  2663.         goto error;
  2664.     }
  2665.  
  2666.     /*
  2667.      * Assume that the geometry information came from the user,
  2668.      * unless an explicit source has been specified.  Otherwise
  2669.      * most window managers assume that the size hints were
  2670.      * program-specified and they ignore them.
  2671.      */
  2672.  
  2673.     if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
  2674.         wmPtr->sizeHintsFlags |= USPosition;
  2675.     }
  2676.     }
  2677.  
  2678.     /*
  2679.      * Everything was parsed OK.  Update the fields of *wmPtr and
  2680.      * arrange for the appropriate information to be percolated out
  2681.      * to the window manager at the next idle moment.
  2682.      */
  2683.  
  2684.     wmPtr->width = width;
  2685.     wmPtr->height = height;
  2686.     wmPtr->x = x;
  2687.     wmPtr->y = y;
  2688.     flags |= WM_MOVE_PENDING;
  2689.     wmPtr->flags = flags;
  2690.  
  2691.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  2692.     Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  2693.     wmPtr->flags |= WM_UPDATE_PENDING;
  2694.     }
  2695.     return TCL_OK;
  2696.  
  2697.     error:
  2698.     Tcl_AppendResult(interp, "bad geometry specifier \"",
  2699.         string, "\"", (char *) NULL);
  2700.     return TCL_ERROR;
  2701. }
  2702.  
  2703. /*
  2704.  *----------------------------------------------------------------------
  2705.  *
  2706.  * Tk_GetRootCoords --
  2707.  *
  2708.  *    Given a token for a window, this procedure traces through the
  2709.  *    window's lineage to find the (virtual) root-window coordinates
  2710.  *    corresponding to point (0,0) in the window.
  2711.  *
  2712.  * Results:
  2713.  *    The locations pointed to by xPtr and yPtr are filled in with
  2714.  *    the root coordinates of the (0,0) point in tkwin.
  2715.  *
  2716.  * Side effects:
  2717.  *    None.
  2718.  *
  2719.  *----------------------------------------------------------------------
  2720.  */
  2721.  
  2722. void
  2723. Tk_GetRootCoords(tkwin, xPtr, yPtr)
  2724.     Tk_Window tkwin;        /* Token for window. */
  2725.     int *xPtr;            /* Where to store x-displacement of (0,0). */
  2726.     int *yPtr;            /* Where to store y-displacement of (0,0). */
  2727. {
  2728.     register TkWindow *winPtr = (TkWindow *) tkwin;
  2729.  
  2730.     /*
  2731.      * If the window is mapped, let Windows figure out the translation.
  2732.      */
  2733.  
  2734.     if (winPtr->window != None) {
  2735.     HWND hwnd = Tk_GetHWND(winPtr->window);
  2736.     POINT point;
  2737.  
  2738.     point.x = 0;
  2739.     point.y = 0;
  2740.  
  2741.     ClientToScreen(hwnd, &point);
  2742.  
  2743.     *xPtr = point.x;
  2744.     *yPtr = point.y;
  2745.     } else {
  2746.     *xPtr = 0;
  2747.     *yPtr = 0;
  2748.     }
  2749. }
  2750.  
  2751. /*
  2752.  *----------------------------------------------------------------------
  2753.  *
  2754.  * Tk_CoordsToWindow --
  2755.  *
  2756.  *    Given the (virtual) root coordinates of a point, this procedure
  2757.  *    returns the token for the top-most window covering that point,
  2758.  *    if there exists such a window in this application.
  2759.  *
  2760.  * Results:
  2761.  *    The return result is either a token for the window corresponding
  2762.  *    to rootX and rootY, or else NULL to indicate that there is no such
  2763.  *    window.
  2764.  *
  2765.  * Side effects:
  2766.  *    None.
  2767.  *
  2768.  *----------------------------------------------------------------------
  2769.  */
  2770.  
  2771. Tk_Window
  2772. Tk_CoordsToWindow(rootX, rootY, tkwin)
  2773.     int rootX, rootY;        /* Coordinates of point in root window.  If
  2774.                  * a virtual-root window manager is in use,
  2775.                  * these coordinates refer to the virtual
  2776.                  * root, not the real root. */
  2777.     Tk_Window tkwin;        /* Token for any window in application;
  2778.                  * used to identify the display. */
  2779. {
  2780.     POINT pos;
  2781.     HWND hwnd;
  2782.     TkWindow *winPtr;
  2783.  
  2784.     pos.x = rootX;
  2785.     pos.y = rootY;
  2786.     hwnd = WindowFromPoint(pos);
  2787.  
  2788.     winPtr = (TkWindow *) Tk_HWNDToWindow(hwnd);
  2789.     if (winPtr && (winPtr->mainPtr == ((TkWindow *) tkwin)->mainPtr)) {
  2790.     return (Tk_Window) winPtr;
  2791.     }
  2792.     return NULL;
  2793. }
  2794.  
  2795. /*
  2796.  *----------------------------------------------------------------------
  2797.  *
  2798.  * Tk_GetVRootGeometry --
  2799.  *
  2800.  *    This procedure returns information about the virtual root
  2801.  *    window corresponding to a particular Tk window.
  2802.  *
  2803.  * Results:
  2804.  *    The values at xPtr, yPtr, widthPtr, and heightPtr are set
  2805.  *    with the offset and dimensions of the root window corresponding
  2806.  *    to tkwin.  If tkwin is being managed by a virtual root window
  2807.  *    manager these values correspond to the virtual root window being
  2808.  *    used for tkwin;  otherwise the offsets will be 0 and the
  2809.  *    dimensions will be those of the screen.
  2810.  *
  2811.  * Side effects:
  2812.  *    Vroot window information is refreshed if it is out of date.
  2813.  *
  2814.  *----------------------------------------------------------------------
  2815.  */
  2816.  
  2817. void
  2818. Tk_GetVRootGeometry(tkwin, xPtr, yPtr, widthPtr, heightPtr)
  2819.     Tk_Window tkwin;        /* Window whose virtual root is to be
  2820.                  * queried. */
  2821.     int *xPtr, *yPtr;        /* Store x and y offsets of virtual root
  2822.                  * here. */
  2823.     int *widthPtr, *heightPtr;    /* Store dimensions of virtual root here. */
  2824. {
  2825.     TkWindow *winPtr = (TkWindow *) tkwin;
  2826.  
  2827.     *xPtr = 0;
  2828.     *yPtr = 0;
  2829.     *widthPtr = DisplayWidth(winPtr->display, winPtr->screenNum);
  2830.     *heightPtr = DisplayHeight(winPtr->display, winPtr->screenNum);
  2831. }
  2832.  
  2833. /*
  2834.  *----------------------------------------------------------------------
  2835.  *
  2836.  * Tk_MoveToplevelWindow --
  2837.  *
  2838.  *    This procedure is called instead of Tk_MoveWindow to adjust
  2839.  *    the x-y location of a top-level window.  It delays the actual
  2840.  *    move to a later time and keeps window-manager information
  2841.  *    up-to-date with the move
  2842.  *
  2843.  * Results:
  2844.  *    None.
  2845.  *
  2846.  * Side effects:
  2847.  *    The window is eventually moved so that its upper-left corner
  2848.  *    (actually, the upper-left corner of the window's decorative
  2849.  *    frame, if there is one) is at (x,y).
  2850.  *
  2851.  *----------------------------------------------------------------------
  2852.  */
  2853.  
  2854. void
  2855. Tk_MoveToplevelWindow(tkwin, x, y)
  2856.     Tk_Window tkwin;        /* Window to move. */
  2857.     int x, y;            /* New location for window (within
  2858.                  * parent). */
  2859. {
  2860.     TkWindow *winPtr = (TkWindow *) tkwin;
  2861.     register WmInfo *wmPtr = winPtr->wmInfoPtr;
  2862.  
  2863.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  2864.     panic("Tk_MoveToplevelWindow called with non-toplevel window");
  2865.     }
  2866.     wmPtr->x = x;
  2867.     wmPtr->y = y;
  2868.     wmPtr->flags |= WM_MOVE_PENDING;
  2869.     wmPtr->flags &= ~(WM_NEGATIVE_X|WM_NEGATIVE_Y);
  2870.     if ((wmPtr->sizeHintsFlags & (USPosition|PPosition)) == 0) {
  2871.     wmPtr->sizeHintsFlags |= USPosition;
  2872.     }
  2873.  
  2874.     /*
  2875.      * If the window has already been mapped, must bring its geometry
  2876.      * up-to-date immediately, otherwise an event might arrive from the
  2877.      * server that would overwrite wmPtr->x and wmPtr->y and lose the
  2878.      * new position.
  2879.      */
  2880.  
  2881.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  2882.     if (wmPtr->flags & WM_UPDATE_PENDING) {
  2883.         Tcl_CancelIdleCall(UpdateGeometryInfo, (ClientData) winPtr);
  2884.     }
  2885.     UpdateGeometryInfo((ClientData) winPtr);
  2886.     }
  2887. }
  2888.  
  2889. /*
  2890.  *----------------------------------------------------------------------
  2891.  *
  2892.  * TkWmProtocolEventProc --
  2893.  *
  2894.  *    This procedure is called by the Tk_HandleEvent whenever a
  2895.  *    ClientMessage event arrives whose type is "WM_PROTOCOLS".
  2896.  *    This procedure handles the message from the window manager
  2897.  *    in an appropriate fashion.
  2898.  *
  2899.  * Results:
  2900.  *    None.
  2901.  *
  2902.  * Side effects:
  2903.  *    Depends on what sort of handler, if any, was set up for the
  2904.  *    protocol.
  2905.  *
  2906.  *----------------------------------------------------------------------
  2907.  */
  2908.  
  2909. void
  2910. TkWmProtocolEventProc(winPtr, eventPtr)
  2911.     TkWindow *winPtr;        /* Window to which the event was sent. */
  2912.     XEvent *eventPtr;        /* X event. */
  2913. {
  2914.     WmInfo *wmPtr;
  2915.     register ProtocolHandler *protPtr;
  2916.     Atom protocol;
  2917.     int result;
  2918.     Tcl_Interp *interp;
  2919.  
  2920.     wmPtr = winPtr->wmInfoPtr;
  2921.     if (wmPtr == NULL) {
  2922.     return;
  2923.     }
  2924.     protocol = (Atom) eventPtr->xclient.data.l[0];
  2925.     for (protPtr = wmPtr->protPtr; protPtr != NULL;
  2926.         protPtr = protPtr->nextPtr) {
  2927.     if (protocol == protPtr->protocol) {
  2928.         Tcl_Preserve((ClientData) protPtr);
  2929.             interp = protPtr->interp;
  2930.             Tcl_Preserve((ClientData) interp);
  2931.         result = Tcl_GlobalEval(interp, protPtr->command);
  2932.         if (result != TCL_OK) {
  2933.         Tcl_AddErrorInfo(interp, "\n    (command for \"");
  2934.         Tcl_AddErrorInfo(interp,
  2935.             Tk_GetAtomName((Tk_Window) winPtr, protocol));
  2936.         Tcl_AddErrorInfo(interp, "\" window manager protocol)");
  2937.         Tcl_BackgroundError(interp);
  2938.         }
  2939.             Tcl_Release((ClientData) interp);
  2940.         Tcl_Release((ClientData) protPtr);
  2941.         return;
  2942.     }
  2943.     }
  2944.  
  2945.     /*
  2946.      * No handler was present for this protocol.  If this is a
  2947.      * WM_DELETE_WINDOW message then just destroy the window.
  2948.      */
  2949.  
  2950.     if (protocol == Tk_InternAtom((Tk_Window) winPtr, "WM_DELETE_WINDOW")) {
  2951.     Tk_DestroyWindow((Tk_Window) winPtr);
  2952.     }
  2953. }
  2954.  
  2955. /*
  2956.  *----------------------------------------------------------------------
  2957.  *
  2958.  * TkWmRestackToplevel --
  2959.  *
  2960.  *    This procedure restacks a top-level window.
  2961.  *
  2962.  * Results:
  2963.  *    None.
  2964.  *
  2965.  * Side effects:
  2966.  *    WinPtr gets restacked  as specified by aboveBelow and otherPtr.
  2967.  *    This procedure doesn't return until the restack has taken
  2968.  *    effect and the ConfigureNotify event for it has been received.
  2969.  *
  2970.  *----------------------------------------------------------------------
  2971.  */
  2972.  
  2973. void
  2974. TkWmRestackToplevel(winPtr, aboveBelow, otherPtr)
  2975.     TkWindow *winPtr;        /* Window to restack. */
  2976.     int aboveBelow;        /* Gives relative position for restacking;
  2977.                  * must be Above or Below. */
  2978.     TkWindow *otherPtr;        /* Window relative to which to restack;
  2979.                  * if NULL, then winPtr gets restacked
  2980.                  * above or below *all* siblings. */
  2981. {
  2982.     HWND hwnd, insertAfter;
  2983.  
  2984.     /*
  2985.      * Can't set stacking order properly until the window is on the
  2986.      * screen (mapping it may give it a reparent window).
  2987.      */
  2988.  
  2989.     if (winPtr->window == None) {
  2990.     Tk_MakeWindowExist((Tk_Window) winPtr);
  2991.     }
  2992.     if (winPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
  2993.     TkWmMapWindow(winPtr);
  2994.     }
  2995.     hwnd = (winPtr->wmInfoPtr->wrapper != NULL)
  2996.     ? winPtr->wmInfoPtr->wrapper : Tk_GetHWND(winPtr->window);
  2997.  
  2998.     
  2999.     if (otherPtr != NULL) {
  3000.     if (otherPtr->window == None) {
  3001.         Tk_MakeWindowExist((Tk_Window) otherPtr);
  3002.     }
  3003.     if (otherPtr->wmInfoPtr->flags & WM_NEVER_MAPPED) {
  3004.         TkWmMapWindow(otherPtr);
  3005.     }
  3006.     insertAfter = (otherPtr->wmInfoPtr->wrapper != NULL)
  3007.         ? otherPtr->wmInfoPtr->wrapper : Tk_GetHWND(otherPtr->window);
  3008.     } else {
  3009.     insertAfter = NULL;
  3010.     }
  3011.  
  3012.     TkWinSetWindowPos(hwnd, insertAfter, aboveBelow);
  3013. }
  3014.  
  3015. /*
  3016.  *----------------------------------------------------------------------
  3017.  *
  3018.  * TkWmAddToColormapWindows --
  3019.  *
  3020.  *    This procedure is called to add a given window to the
  3021.  *    WM_COLORMAP_WINDOWS property for its top-level, if it
  3022.  *    isn't already there.  It is invoked by the Tk code that
  3023.  *    creates a new colormap, in order to make sure that colormap
  3024.  *    information is propagated to the window manager by default.
  3025.  *
  3026.  * Results:
  3027.  *    None.
  3028.  *
  3029.  * Side effects:
  3030.  *    WinPtr's window gets added to the WM_COLORMAP_WINDOWS
  3031.  *    property of its nearest top-level ancestor, unless the
  3032.  *    colormaps have been set explicitly with the
  3033.  *    "wm colormapwindows" command.
  3034.  *
  3035.  *----------------------------------------------------------------------
  3036.  */
  3037.  
  3038. void
  3039. TkWmAddToColormapWindows(winPtr)
  3040.     TkWindow *winPtr;        /* Window with a non-default colormap.
  3041.                  * Should not be a top-level window. */
  3042. {
  3043.     TkWindow *topPtr;
  3044.     TkWindow **oldPtr, **newPtr;
  3045.     int count, i;
  3046.  
  3047.     if (winPtr->window == None) {
  3048.     return;
  3049.     }
  3050.  
  3051.     for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
  3052.     if (topPtr == NULL) {
  3053.         /*
  3054.          * Window is being deleted.  Skip the whole operation.
  3055.          */
  3056.  
  3057.         return;
  3058.     }
  3059.     if (topPtr->flags & TK_TOP_LEVEL) {
  3060.         break;
  3061.     }
  3062.     }
  3063.     if (topPtr->wmInfoPtr->flags & WM_COLORMAPS_EXPLICIT) {
  3064.     return;
  3065.     }
  3066.  
  3067.     /*
  3068.      * Make sure that the window isn't already in the list.
  3069.      */
  3070.  
  3071.     count = topPtr->wmInfoPtr->cmapCount;
  3072.     oldPtr = topPtr->wmInfoPtr->cmapList;
  3073.  
  3074.     for (i = 0; i < count; i++) {
  3075.     if (oldPtr[i] == winPtr) {
  3076.         return;
  3077.     }
  3078.     }
  3079.  
  3080.     /*
  3081.      * Make a new bigger array and use it to reset the property.
  3082.      * Automatically add the toplevel itself as the last element
  3083.      * of the list.
  3084.      */
  3085.  
  3086.     newPtr = (TkWindow **) ckalloc((unsigned) ((count+2)*sizeof(TkWindow*)));
  3087.     if (count > 0) {
  3088.     memcpy(newPtr, oldPtr, count * sizeof(TkWindow*));
  3089.     }
  3090.     if (count == 0) {
  3091.     count++;
  3092.     }
  3093.     newPtr[count-1] = winPtr;
  3094.     newPtr[count] = topPtr;
  3095.     if (oldPtr != NULL) {
  3096.     ckfree((char *) oldPtr);
  3097.     }
  3098.  
  3099.     topPtr->wmInfoPtr->cmapList = newPtr;
  3100.     topPtr->wmInfoPtr->cmapCount = count+1;
  3101.  
  3102.     /*
  3103.      * Now we need to force the updated colormaps to be installed.
  3104.      */
  3105.  
  3106.     if (topPtr->wmInfoPtr == foregroundWmPtr) {
  3107.     InstallColormaps(topPtr->wmInfoPtr->wrapper, WM_QUERYNEWPALETTE, 1);
  3108.     } else {
  3109.     InstallColormaps(topPtr->wmInfoPtr->wrapper, WM_PALETTECHANGED, 0);
  3110.     }
  3111. }
  3112.  
  3113. /*
  3114.  *----------------------------------------------------------------------
  3115.  *
  3116.  * TkWmRemoveFromColormapWindows --
  3117.  *
  3118.  *    This procedure is called to remove a given window from the
  3119.  *    WM_COLORMAP_WINDOWS property for its top-level.  It is invoked
  3120.  *    when windows are deleted.
  3121.  *
  3122.  * Results:
  3123.  *    None.
  3124.  *
  3125.  * Side effects:
  3126.  *    WinPtr's window gets removed from the WM_COLORMAP_WINDOWS
  3127.  *    property of its nearest top-level ancestor, unless the
  3128.  *    top-level itself is being deleted too.
  3129.  *
  3130.  *----------------------------------------------------------------------
  3131.  */
  3132.  
  3133. void
  3134. TkWmRemoveFromColormapWindows(winPtr)
  3135.     TkWindow *winPtr;        /* Window that may be present in
  3136.                  * WM_COLORMAP_WINDOWS property for its
  3137.                  * top-level.  Should not be a top-level
  3138.                  * window. */
  3139. {
  3140.     TkWindow *topPtr;
  3141.     TkWindow **oldPtr;
  3142.     int count, i, j;
  3143.  
  3144.     for (topPtr = winPtr->parentPtr; ; topPtr = topPtr->parentPtr) {
  3145.     if (topPtr == NULL) {
  3146.         /*
  3147.          * Ancestors have been deleted, so skip the whole operation.
  3148.          * Seems like this can't ever happen?
  3149.          */
  3150.  
  3151.         return;
  3152.     }
  3153.     if (topPtr->flags & TK_TOP_LEVEL) {
  3154.         break;
  3155.     }
  3156.     }
  3157.     if (topPtr->flags & TK_ALREADY_DEAD) {
  3158.     /*
  3159.      * Top-level is being deleted, so there's no need to cleanup
  3160.      * the WM_COLORMAP_WINDOWS property.
  3161.      */
  3162.  
  3163.     return;
  3164.     }
  3165.  
  3166.     /*
  3167.      * Find the window and slide the following ones down to cover
  3168.      * it up.
  3169.      */
  3170.  
  3171.     count = topPtr->wmInfoPtr->cmapCount;
  3172.     oldPtr = topPtr->wmInfoPtr->cmapList;
  3173.     for (i = 0; i < count; i++) {
  3174.     if (oldPtr[i] == winPtr) {
  3175.         for (j = i ; j < count-1; j++) {
  3176.         oldPtr[j] = oldPtr[j+1];
  3177.         }
  3178.         topPtr->wmInfoPtr->cmapCount = count-1;
  3179.         break;
  3180.     }
  3181.     }
  3182. }
  3183.  
  3184. /*
  3185.  *----------------------------------------------------------------------
  3186.  *
  3187.  * TkWinSetMenu--
  3188.  *
  3189.  *    Associcates a given HMENU to a window.
  3190.  *
  3191.  * Results:
  3192.  *    None.
  3193.  *
  3194.  * Side effects:
  3195.  *    The menu will end up being drawn in the window, and the geometry
  3196.  *    of the window will have to be changed.
  3197.  *
  3198.  *----------------------------------------------------------------------
  3199.  */
  3200.  
  3201. void
  3202. TkWinSetMenu(tkwin, hMenu)
  3203.     Tk_Window tkwin;        /* the window to put the menu in */
  3204.     HMENU hMenu;        /* the menu to set */
  3205. {
  3206.     TkWindow *winPtr = (TkWindow *) tkwin;
  3207.     WmInfo *wmPtr = winPtr->wmInfoPtr;
  3208.  
  3209.     wmPtr->hMenu = hMenu;
  3210.  
  3211.     if (!(wmPtr->flags & TK_EMBEDDED)) {
  3212.     if (!(wmPtr->flags & WM_NEVER_MAPPED)) {
  3213.         int syncPending = wmPtr->flags & WM_SYNC_PENDING;
  3214.  
  3215.         wmPtr->flags |= WM_SYNC_PENDING;
  3216.         SetMenu(wmPtr->wrapper, hMenu);
  3217.         if (!syncPending) {
  3218.         wmPtr->flags &= ~WM_SYNC_PENDING;
  3219.         }
  3220.     }
  3221.     if (!(wmPtr->flags & (WM_UPDATE_PENDING|WM_NEVER_MAPPED))) {
  3222.         Tcl_DoWhenIdle(UpdateGeometryInfo, (ClientData) winPtr);
  3223.         wmPtr->flags |= WM_UPDATE_PENDING|WM_MOVE_PENDING;
  3224.     }
  3225.     }
  3226. }
  3227.  
  3228. /*
  3229.  *----------------------------------------------------------------------
  3230.  *
  3231.  * ConfigureTopLevel --
  3232.  *
  3233.  *    Generate a ConfigureNotify event based on the current position
  3234.  *    information.  This procedure is called by TopLevelProc.
  3235.  *
  3236.  * Results:
  3237.  *    None.
  3238.  *
  3239.  * Side effects:
  3240.  *    Queues a new event.
  3241.  *
  3242.  *----------------------------------------------------------------------
  3243.  */
  3244.  
  3245. static void
  3246. ConfigureTopLevel(pos)
  3247.     WINDOWPOS *pos;
  3248. {
  3249.     TkWindow *winPtr = GetTopLevel(pos->hwnd);
  3250.     WmInfo *wmPtr;
  3251.     int state;            /* Current window state. */
  3252.     RECT rect;
  3253.     WINDOWPLACEMENT windowPos;
  3254.     
  3255.     if (winPtr == NULL) {
  3256.     return;
  3257.     }
  3258.  
  3259.     wmPtr = winPtr->wmInfoPtr;
  3260.  
  3261.     /*
  3262.      * Determine the current window state.
  3263.      */
  3264.  
  3265.     if (!IsWindowVisible(wmPtr->wrapper)) {
  3266.     state = WithdrawnState;
  3267.     } else {
  3268.     windowPos.length = sizeof(WINDOWPLACEMENT);
  3269.     GetWindowPlacement(wmPtr->wrapper, &windowPos);
  3270.     switch (windowPos.showCmd) {
  3271.         case SW_SHOWMAXIMIZED:
  3272.         state = ZoomState;
  3273.         break;
  3274.         case SW_SHOWMINIMIZED:
  3275.         state = IconicState;
  3276.         break;
  3277.         case SW_SHOWNORMAL:
  3278.         state = NormalState;
  3279.         break;
  3280.     }
  3281.     }
  3282.  
  3283.     /*
  3284.      * If the state of the window just changed, be sure to update the
  3285.      * child window information.
  3286.      */
  3287.  
  3288.     if (wmPtr->hints.initial_state != state) {
  3289.     wmPtr->hints.initial_state = state;
  3290.     switch (state) {
  3291.         case WithdrawnState:
  3292.         case IconicState:
  3293.         XUnmapWindow(winPtr->display, winPtr->window);
  3294.         break;
  3295.  
  3296.         case NormalState:
  3297.         /*
  3298.          * Schedule a geometry update.  Since we ignore geometry
  3299.          * requests while in any other state, the geometry info
  3300.          * may be stale.
  3301.          */
  3302.  
  3303.         if (!(wmPtr->flags & WM_UPDATE_PENDING)) {
  3304.             Tcl_DoWhenIdle(UpdateGeometryInfo,
  3305.                 (ClientData) winPtr);
  3306.             wmPtr->flags |= WM_UPDATE_PENDING;
  3307.         }
  3308.         /* fall through */
  3309.         case ZoomState:
  3310.         XMapWindow(winPtr->display, winPtr->window);
  3311.         pos->flags |= SWP_NOMOVE | SWP_NOSIZE;
  3312.         break;
  3313.     }
  3314.     }
  3315.  
  3316.     /*
  3317.      * Don't report geometry changes in the Iconic or Withdrawn states.
  3318.      */
  3319.  
  3320.     if (state == WithdrawnState || state == IconicState) {
  3321.     return;
  3322.     }
  3323.  
  3324.  
  3325.     /*
  3326.      * Compute the current geometry of the client area, reshape the
  3327.      * Tk window and generate a ConfigureNotify event.
  3328.      */
  3329.  
  3330.     GetClientRect(wmPtr->wrapper, &rect);
  3331.     winPtr->changes.x = pos->x;
  3332.     winPtr->changes.y = pos->y;
  3333.     winPtr->changes.width = rect.right - rect.left;
  3334.     winPtr->changes.height = rect.bottom - rect.top;
  3335.     wmPtr->borderHeight = pos->cy - winPtr->changes.height;
  3336.     MoveWindow(Tk_GetHWND(winPtr->window), 0, 0,
  3337.         winPtr->changes.width, winPtr->changes.height, TRUE);
  3338.     GenerateConfigureNotify(winPtr);
  3339.  
  3340.     /*
  3341.      * Update window manager geometry info if needed.
  3342.      */
  3343.  
  3344.     if (state == NormalState) {
  3345.  
  3346.     /* 
  3347.      * Update size information from the event.  There are a couple of
  3348.      * tricky points here:
  3349.      *
  3350.      * 1. If the user changed the size externally then set wmPtr->width
  3351.      *    and wmPtr->height just as if a "wm geometry" command had been
  3352.      *    invoked with the same information.
  3353.      * 2. However, if the size is changing in response to a request
  3354.      *    coming from us (sync is set), then don't set
  3355.      *    wmPtr->width or wmPtr->height (otherwise the window will stop
  3356.      *    tracking geometry manager requests).
  3357.      */
  3358.  
  3359.     if (!(wmPtr->flags & WM_SYNC_PENDING)) {
  3360.         if (!(pos->flags & SWP_NOSIZE)) {
  3361.         if ((wmPtr->width == -1)
  3362.             && (winPtr->changes.width == winPtr->reqWidth)) {
  3363.             /*
  3364.              * Don't set external width, since the user didn't
  3365.              * change it from what the widgets asked for.
  3366.              */
  3367.         } else {
  3368.             if (wmPtr->gridWin != NULL) {
  3369.             wmPtr->width = wmPtr->reqGridWidth
  3370.                 + (winPtr->changes.width - winPtr->reqWidth)
  3371.                 / wmPtr->widthInc;
  3372.             if (wmPtr->width < 0) {
  3373.                 wmPtr->width = 0;
  3374.             }
  3375.             } else {
  3376.             wmPtr->width = winPtr->changes.width;
  3377.             }
  3378.         }
  3379.         if ((wmPtr->height == -1)
  3380.             && (winPtr->changes.height == winPtr->reqHeight)) {
  3381.             /*
  3382.              * Don't set external height, since the user didn't change
  3383.              * it from what the widgets asked for.
  3384.              */
  3385.         } else {
  3386.             if (wmPtr->gridWin != NULL) {
  3387.             wmPtr->height = wmPtr->reqGridHeight
  3388.                 + (winPtr->changes.height - winPtr->reqHeight)
  3389.                 / wmPtr->heightInc;
  3390.             if (wmPtr->height < 0) {
  3391.                 wmPtr->height = 0;
  3392.             }
  3393.             } else {
  3394.             wmPtr->height = winPtr->changes.height;
  3395.             }
  3396.         }
  3397.         wmPtr->configWidth = winPtr->changes.width;
  3398.         wmPtr->configHeight = winPtr->changes.height;
  3399.         }
  3400.         /*
  3401.          * If the user moved the window, we should switch back
  3402.          * to normal coordinates.
  3403.          */
  3404.  
  3405.         if (!(pos->flags & SWP_NOMOVE)) {
  3406.         wmPtr->flags &= ~(WM_NEGATIVE_X | WM_NEGATIVE_Y);
  3407.         }
  3408.     }
  3409.    
  3410.     /*
  3411.      * Update the wrapper window location information. 
  3412.      */
  3413.  
  3414.     if (wmPtr->flags & WM_NEGATIVE_X) {
  3415.         wmPtr->x = DisplayWidth(winPtr->display, winPtr->screenNum)
  3416.         - winPtr->changes.x - (winPtr->changes.width
  3417.             + wmPtr->borderWidth);
  3418.     } else {
  3419.         wmPtr->x = winPtr->changes.x;
  3420.     }
  3421.     if (wmPtr->flags & WM_NEGATIVE_Y) {
  3422.         wmPtr->y = DisplayHeight(winPtr->display, winPtr->screenNum)
  3423.         - winPtr->changes.y - (winPtr->changes.height
  3424.             + wmPtr->borderHeight);
  3425.     } else {
  3426.         wmPtr->y = winPtr->changes.y;
  3427.     }
  3428.     }
  3429. }
  3430.  
  3431. /*
  3432.  *----------------------------------------------------------------------
  3433.  *
  3434.  * GenerateConfigureNotify --
  3435.  *
  3436.  *    Generate a ConfigureNotify event from the current geometry
  3437.  *    information for the specified toplevel window.
  3438.  *
  3439.  * Results:
  3440.  *    None.
  3441.  *
  3442.  * Side effects:
  3443.  *    Sends an X event.
  3444.  *
  3445.  *----------------------------------------------------------------------
  3446.  */
  3447.  
  3448. static void
  3449. GenerateConfigureNotify(winPtr)
  3450.     TkWindow *winPtr;
  3451. {
  3452.     XEvent event;
  3453.  
  3454.     /*
  3455.      * Generate a ConfigureNotify event.
  3456.      */
  3457.  
  3458.     event.type = ConfigureNotify;
  3459.     event.xconfigure.serial = winPtr->display->request;
  3460.     event.xconfigure.send_event = False;
  3461.     event.xconfigure.display = winPtr->display;
  3462.     event.xconfigure.event = winPtr->window;
  3463.     event.xconfigure.window = winPtr->window;
  3464.     event.xconfigure.border_width = winPtr->changes.border_width;
  3465.     event.xconfigure.override_redirect = winPtr->atts.override_redirect;
  3466.     event.xconfigure.x = winPtr->changes.x;
  3467.     event.xconfigure.y = winPtr->changes.y;
  3468.     event.xconfigure.width = winPtr->changes.width;
  3469.     event.xconfigure.height = winPtr->changes.height;
  3470.     event.xconfigure.above = None;
  3471.     Tk_QueueWindowEvent(&event, TCL_QUEUE_TAIL);
  3472. }
  3473.  
  3474. /*
  3475.  *----------------------------------------------------------------------
  3476.  *
  3477.  * InstallColormaps --
  3478.  *
  3479.  *    Installs the colormaps associated with the toplevel which is
  3480.  *    currently active.
  3481.  *
  3482.  * Results:
  3483.  *    None.
  3484.  *
  3485.  * Side effects:
  3486.  *    May change the system palette and generate damage.
  3487.  *
  3488.  *----------------------------------------------------------------------
  3489.  */
  3490.  
  3491. static int
  3492. InstallColormaps(hwnd, message, isForemost)
  3493.     HWND hwnd;            /* Toplevel wrapper window whose colormaps
  3494.                  * should be installed. */
  3495.     int message;        /* Either WM_PALETTECHANGED or
  3496.                  * WM_QUERYNEWPALETTE */
  3497.     int isForemost;        /* 1 if window is foremost, else 0 */
  3498. {
  3499.     int i;
  3500.     HDC dc;
  3501.     HPALETTE oldPalette;
  3502.     TkWindow *winPtr = GetTopLevel(hwnd);
  3503.     WmInfo *wmPtr;
  3504.         
  3505.     if (winPtr == NULL) {
  3506.     return 0;
  3507.     }
  3508.  
  3509.     wmPtr = winPtr->wmInfoPtr;
  3510.  
  3511.     if (message == WM_QUERYNEWPALETTE) {
  3512.     /*
  3513.      * Case 1: This window is about to become the foreground window, so we
  3514.      * need to install the primary palette. If the system palette was
  3515.      * updated, then Windows will generate a WM_PALETTECHANGED message.
  3516.      * Otherwise, we have to synthesize one in order to ensure that the
  3517.      * secondary palettes are installed properly.
  3518.      */
  3519.  
  3520.     foregroundWmPtr = wmPtr;
  3521.  
  3522.     if (wmPtr->cmapCount > 0) {
  3523.         winPtr = wmPtr->cmapList[0];
  3524.     }
  3525.  
  3526.     systemPalette = TkWinGetPalette(winPtr->atts.colormap);
  3527.     dc = GetDC(hwnd);
  3528.     oldPalette = SelectPalette(dc, systemPalette, FALSE);
  3529.     if (RealizePalette(dc)) {
  3530.         RefreshColormap(winPtr->atts.colormap);
  3531.     } else if (wmPtr->cmapCount > 1) {
  3532.         SelectPalette(dc, oldPalette, TRUE);
  3533.         RealizePalette(dc);
  3534.         ReleaseDC(hwnd, dc);
  3535.         SendMessage(hwnd, WM_PALETTECHANGED, (WPARAM)hwnd,
  3536.             (LPARAM)NULL);
  3537.         return TRUE;
  3538.     }
  3539.  
  3540.     } else {
  3541.     /*
  3542.      * Window is being notified of a change in the system palette.
  3543.      * If this window is the foreground window, then we should only
  3544.      * install the secondary palettes, since the primary was installed
  3545.      * in response to the WM_QUERYPALETTE message.  Otherwise, install
  3546.      * all of the palettes.
  3547.      */
  3548.  
  3549.  
  3550.     if (!isForemost) {
  3551.         if (wmPtr->cmapCount > 0) {
  3552.         winPtr = wmPtr->cmapList[0];
  3553.         }
  3554.         i = 1;
  3555.     } else {
  3556.         if (wmPtr->cmapCount <= 1) {
  3557.         return TRUE;
  3558.         }
  3559.         winPtr = wmPtr->cmapList[1];
  3560.         i = 2;
  3561.     }
  3562.     dc = GetDC(hwnd);
  3563.     oldPalette = SelectPalette(dc,
  3564.         TkWinGetPalette(winPtr->atts.colormap), TRUE);
  3565.     if (RealizePalette(dc)) {
  3566.         RefreshColormap(winPtr->atts.colormap);
  3567.     }
  3568.     for (; i < wmPtr->cmapCount; i++) {
  3569.         winPtr = wmPtr->cmapList[i];
  3570.         SelectPalette(dc, TkWinGetPalette(winPtr->atts.colormap), TRUE);
  3571.         if (RealizePalette(dc)) {
  3572.         RefreshColormap(winPtr->atts.colormap);
  3573.         }
  3574.     }
  3575.     }
  3576.  
  3577.     SelectPalette(dc, oldPalette, TRUE);
  3578.     RealizePalette(dc);
  3579.     ReleaseDC(hwnd, dc);
  3580.     return TRUE;
  3581. }
  3582.  
  3583. /*
  3584.  *----------------------------------------------------------------------
  3585.  *
  3586.  * RefreshColormap --
  3587.  *
  3588.  *    This function is called to force all of the windows that use
  3589.  *    a given colormap to redraw themselves.  The quickest way to
  3590.  *    do this is to iterate over the toplevels, looking in the
  3591.  *    cmapList for matches.  This will quickly eliminate subtrees
  3592.  *    that don't use a given colormap.
  3593.  *
  3594.  * Results:
  3595.  *    None.
  3596.  *
  3597.  * Side effects:
  3598.  *    Causes damage events to be generated.
  3599.  *
  3600.  *----------------------------------------------------------------------
  3601.  */
  3602.  
  3603. static void
  3604. RefreshColormap(colormap)
  3605.     Colormap colormap;
  3606. {
  3607.     WmInfo *wmPtr;
  3608.     int i;
  3609.  
  3610.     for (wmPtr = firstWmPtr; wmPtr != NULL; wmPtr = wmPtr->nextPtr) {
  3611.     if (wmPtr->cmapCount > 0) {
  3612.         for (i = 0; i < wmPtr->cmapCount; i++) {
  3613.         if ((wmPtr->cmapList[i]->atts.colormap == colormap)
  3614.             && Tk_IsMapped(wmPtr->cmapList[i])) {
  3615.             InvalidateSubTree(wmPtr->cmapList[i], colormap);
  3616.         }
  3617.         }
  3618.     } else if ((wmPtr->winPtr->atts.colormap == colormap)
  3619.         && Tk_IsMapped(wmPtr->winPtr)) {
  3620.         InvalidateSubTree(wmPtr->winPtr, colormap);
  3621.     }
  3622.     }
  3623. }
  3624.  
  3625. /*
  3626.  *----------------------------------------------------------------------
  3627.  *
  3628.  * InvalidateSubTree --
  3629.  *
  3630.  *    This function recursively generates damage for a window and
  3631.  *    all of its mapped children that belong to the same toplevel and
  3632.  *    are using the specified colormap.
  3633.  *
  3634.  * Results:
  3635.  *    None.
  3636.  *
  3637.  * Side effects:
  3638.  *    Generates damage for the specified subtree.
  3639.  *
  3640.  *----------------------------------------------------------------------
  3641.  */
  3642.  
  3643. static void
  3644. InvalidateSubTree(winPtr, colormap)
  3645.     TkWindow *winPtr;
  3646.     Colormap colormap;
  3647. {
  3648.     TkWindow *childPtr;
  3649.  
  3650.     /*
  3651.      * Generate damage for the current window if it is using the
  3652.      * specified colormap.
  3653.      */
  3654.  
  3655.     if (winPtr->atts.colormap == colormap) {
  3656.     InvalidateRect(Tk_GetHWND(winPtr->window), NULL, FALSE);
  3657.     }
  3658.  
  3659.     for (childPtr = winPtr->childList; childPtr != NULL;
  3660.         childPtr = childPtr->nextPtr) {
  3661.     /*
  3662.      * We can stop the descent when we hit an unmapped or
  3663.      * toplevel window.  
  3664.      */
  3665.  
  3666.     if (!Tk_IsTopLevel(childPtr) && Tk_IsMapped(childPtr)) {
  3667.         InvalidateSubTree(childPtr, colormap);
  3668.     }
  3669.     }
  3670. }
  3671.  
  3672. /*
  3673.  *----------------------------------------------------------------------
  3674.  *
  3675.  * TkWinGetSystemPalette --
  3676.  *
  3677.  *    Retrieves the currently installed foreground palette.
  3678.  *
  3679.  * Results:
  3680.  *    Returns the global foreground palette, if there is one.
  3681.  *    Otherwise, returns NULL.
  3682.  *
  3683.  * Side effects:
  3684.  *    None.
  3685.  *
  3686.  *----------------------------------------------------------------------
  3687.  */
  3688.  
  3689. HPALETTE
  3690. TkWinGetSystemPalette()
  3691. {
  3692.     return systemPalette;
  3693. }
  3694.  
  3695. /*
  3696.  *----------------------------------------------------------------------
  3697.  *
  3698.  * GetMinSize --
  3699.  *
  3700.  *    This procedure computes the current minWidth and minHeight
  3701.  *    values for a window, taking into account the possibility
  3702.  *    that they may be defaulted.
  3703.  *
  3704.  * Results:
  3705.  *    The values at *minWidthPtr and *minHeightPtr are filled
  3706.  *    in with the minimum allowable dimensions of wmPtr's window,
  3707.  *    in grid units.  If the requested minimum is smaller than the
  3708.  *    system required minimum, then this procedure computes the
  3709.  *    smallest size that will satisfy both the system and the
  3710.  *    grid constraints.
  3711.  *
  3712.  * Side effects:
  3713.  *    None.
  3714.  *
  3715.  *----------------------------------------------------------------------
  3716.  */
  3717.  
  3718. static void
  3719. GetMinSize(wmPtr, minWidthPtr, minHeightPtr)
  3720.     WmInfo *wmPtr;        /* Window manager information for the
  3721.                  * window. */
  3722.     int *minWidthPtr;        /* Where to store the current minimum
  3723.                  * width of the window. */
  3724.     int *minHeightPtr;        /* Where to store the current minimum
  3725.                  * height of the window. */
  3726. {
  3727.     int tmp, base;
  3728.     TkWindow *winPtr = wmPtr->winPtr;
  3729.  
  3730.     /*
  3731.      * Compute the minimum width by taking the default client size
  3732.      * and rounding it up to the nearest grid unit.  Return the greater
  3733.      * of the default minimum and the specified minimum.
  3734.      */
  3735.  
  3736.     tmp = wmPtr->defMinWidth - wmPtr->borderWidth;
  3737.     if (tmp < 0) {
  3738.     tmp = 0;
  3739.     }
  3740.     if (wmPtr->gridWin != NULL) {
  3741.     base = winPtr->reqWidth - (wmPtr->reqGridWidth * wmPtr->widthInc);
  3742.     if (base < 0) {
  3743.         base = 0;
  3744.     }
  3745.     tmp = ((tmp - base) + wmPtr->widthInc - 1)/wmPtr->widthInc;
  3746.     }
  3747.     if (tmp < wmPtr->minWidth) {
  3748.     tmp = wmPtr->minWidth;
  3749.     }
  3750.     *minWidthPtr = tmp;
  3751.  
  3752.     /*
  3753.      * Compute the minimum height in a similar fashion.
  3754.      */
  3755.  
  3756.     tmp = wmPtr->defMinHeight - wmPtr->borderHeight;
  3757.     if (tmp < 0) {
  3758.     tmp = 0;
  3759.     }
  3760.     if (wmPtr->gridWin != NULL) {
  3761.     base = winPtr->reqHeight - (wmPtr->reqGridHeight * wmPtr->heightInc);
  3762.     if (base < 0) {
  3763.         base = 0;
  3764.     }
  3765.     tmp = ((tmp - base) + wmPtr->heightInc - 1)/wmPtr->heightInc;
  3766.     }
  3767.     if (tmp < wmPtr->minHeight) {
  3768.     tmp = wmPtr->minHeight;
  3769.     }
  3770.     *minHeightPtr = tmp;
  3771. }
  3772.  
  3773. /*
  3774.  *----------------------------------------------------------------------
  3775.  *
  3776.  * GetMaxSize --
  3777.  *
  3778.  *    This procedure computes the current maxWidth and maxHeight
  3779.  *    values for a window, taking into account the possibility
  3780.  *    that they may be defaulted.
  3781.  *
  3782.  * Results:
  3783.  *    The values at *maxWidthPtr and *maxHeightPtr are filled
  3784.  *    in with the maximum allowable dimensions of wmPtr's window,
  3785.  *    in grid units.  If no maximum has been specified for the
  3786.  *    window, then this procedure computes the largest sizes that
  3787.  *    will fit on the screen.
  3788.  *
  3789.  * Side effects:
  3790.  *    None.
  3791.  *
  3792.  *----------------------------------------------------------------------
  3793.  */
  3794.  
  3795. static void
  3796. GetMaxSize(wmPtr, maxWidthPtr, maxHeightPtr)
  3797.     WmInfo *wmPtr;        /* Window manager information for the
  3798.                  * window. */
  3799.     int *maxWidthPtr;        /* Where to store the current maximum
  3800.                  * width of the window. */
  3801.     int *maxHeightPtr;        /* Where to store the current maximum
  3802.                  * height of the window. */
  3803. {
  3804.     int tmp;
  3805.  
  3806.     if (wmPtr->maxWidth > 0) {
  3807.     *maxWidthPtr = wmPtr->maxWidth;
  3808.     } else {
  3809.     /*
  3810.      * Must compute a default width.  Fill up the display, leaving a
  3811.      * bit of extra space for the window manager's borders.
  3812.      */
  3813.  
  3814.     tmp = wmPtr->defMaxWidth - wmPtr->borderWidth;
  3815.     if (wmPtr->gridWin != NULL) {
  3816.         /*
  3817.          * Gridding is turned on;  convert from pixels to grid units.
  3818.          */
  3819.  
  3820.         tmp = wmPtr->reqGridWidth
  3821.             + (tmp - wmPtr->winPtr->reqWidth)/wmPtr->widthInc;
  3822.     }
  3823.     *maxWidthPtr = tmp;
  3824.     }
  3825.     if (wmPtr->maxHeight > 0) {
  3826.     *maxHeightPtr = wmPtr->maxHeight;
  3827.     } else {
  3828.     tmp = wmPtr->defMaxHeight - wmPtr->borderHeight;
  3829.     if (wmPtr->gridWin != NULL) {
  3830.         tmp = wmPtr->reqGridHeight
  3831.             + (tmp - wmPtr->winPtr->reqHeight)/wmPtr->heightInc;
  3832.     }
  3833.     *maxHeightPtr = tmp;
  3834.     }
  3835. }
  3836.  
  3837. /*
  3838.  *----------------------------------------------------------------------
  3839.  *
  3840.  * TopLevelProc --
  3841.  *
  3842.  *    Callback from Windows whenever an event occurs on a top level
  3843.  *    window.
  3844.  *
  3845.  * Results:
  3846.  *    Standard Windows return value.
  3847.  *
  3848.  * Side effects:
  3849.  *    Default window behavior.
  3850.  *
  3851.  *----------------------------------------------------------------------
  3852.  */
  3853.  
  3854. static LRESULT CALLBACK
  3855. TopLevelProc(hwnd, message, wParam, lParam)
  3856.     HWND hwnd;
  3857.     UINT message;
  3858.     WPARAM wParam;
  3859.     LPARAM lParam;
  3860. {
  3861.     if (message == WM_WINDOWPOSCHANGED) {
  3862.     WINDOWPOS *pos = (WINDOWPOS *) lParam;
  3863.     TkWindow *winPtr = (TkWindow *) Tk_HWNDToWindow(pos->hwnd);
  3864.     
  3865.     if (winPtr == NULL) {
  3866.         return 0;
  3867.     }
  3868.  
  3869.     /*
  3870.      * Update the shape of the contained window.
  3871.      */
  3872.  
  3873.     if (!(pos->flags & SWP_NOSIZE)) {
  3874.         winPtr->changes.width = pos->cx;
  3875.         winPtr->changes.height = pos->cy;
  3876.     }
  3877.     if (!(pos->flags & SWP_NOMOVE)) {
  3878.         winPtr->changes.x = pos->x;
  3879.         winPtr->changes.y = pos->y;
  3880.     }
  3881.  
  3882.     GenerateConfigureNotify(winPtr);
  3883.  
  3884.     Tcl_ServiceAll();
  3885.     return 0;
  3886.     }
  3887.     return TkWinChildProc(hwnd, message, wParam, lParam);
  3888. }
  3889.  
  3890. /*
  3891.  *----------------------------------------------------------------------
  3892.  *
  3893.  * WmProc --
  3894.  *
  3895.  *    Callback from Windows whenever an event occurs on the decorative
  3896.  *    frame.
  3897.  *
  3898.  * Results:
  3899.  *    Standard Windows return value.
  3900.  *
  3901.  * Side effects:
  3902.  *    Default window behavior.
  3903.  *
  3904.  *----------------------------------------------------------------------
  3905.  */
  3906.  
  3907. static LRESULT CALLBACK
  3908. WmProc(hwnd, message, wParam, lParam)
  3909.     HWND hwnd;
  3910.     UINT message;
  3911.     WPARAM wParam;
  3912.     LPARAM lParam;
  3913. {
  3914.     static int inMoveSize = 0;
  3915.     static oldMode;    /* This static is set upon entering move/size mode
  3916.              * and is used to reset the service mode after
  3917.              * leaving move/size mode.  Note that this mechanism
  3918.              * assumes move/size is only one level deep. */
  3919.     LRESULT result;
  3920.     TkWindow *winPtr;
  3921.     
  3922.     if (TkWinHandleMenuEvent(&hwnd, &message, &wParam, &lParam, &result)) {
  3923.     goto done;
  3924.     }
  3925.  
  3926.     switch (message) {
  3927.     case WM_KILLFOCUS:
  3928.     case WM_ERASEBKGND:
  3929.         result = 0;
  3930.         goto done;
  3931.  
  3932.     case WM_ENTERSIZEMOVE:
  3933.         inMoveSize = 1;
  3934.         oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
  3935.         break;
  3936.  
  3937.     case WM_ACTIVATE:
  3938.     case WM_EXITSIZEMOVE:
  3939.         if (inMoveSize) {
  3940.         inMoveSize = 0;
  3941.         Tcl_SetServiceMode(oldMode);
  3942.         }
  3943.         break;
  3944.  
  3945.     case WM_GETMINMAXINFO: 
  3946.         SetLimits(hwnd, (MINMAXINFO *) lParam);
  3947.         result = 0;
  3948.         goto done;
  3949.  
  3950.     case WM_PALETTECHANGED:
  3951.         result = InstallColormaps(hwnd, WM_PALETTECHANGED,
  3952.             hwnd == (HWND)wParam);
  3953.         goto done;
  3954.  
  3955.     case WM_QUERYNEWPALETTE:
  3956.         result = InstallColormaps(hwnd, WM_QUERYNEWPALETTE, TRUE);
  3957.         goto done;
  3958.         
  3959.     case WM_WINDOWPOSCHANGED:
  3960.         ConfigureTopLevel((WINDOWPOS *) lParam);
  3961.         result = 0;
  3962.         goto done;
  3963.  
  3964.     default:
  3965.         break;
  3966.     }
  3967.  
  3968.     winPtr = GetTopLevel(hwnd);
  3969.     if (winPtr && winPtr->window) {
  3970.     HWND child = Tk_GetHWND(winPtr->window);
  3971.     if (message == WM_SETFOCUS) {
  3972.         SetFocus(child);
  3973.         result = 0;
  3974.     } else if (!Tk_TranslateWinEvent(child, message, wParam, lParam,
  3975.         &result)) {
  3976.         result = DefWindowProc(hwnd, message, wParam, lParam);
  3977.     }
  3978.     } else {
  3979.     result = DefWindowProc(hwnd, message, wParam, lParam);
  3980.     }
  3981.  
  3982.     done:
  3983.     Tcl_ServiceAll();
  3984.     return result;
  3985. }
  3986.  
  3987. /*
  3988.  *----------------------------------------------------------------------
  3989.  *
  3990.  * TkMakeMenuWindow --
  3991.  *
  3992.  *    Configure the window to be either a pull-down (or pop-up)
  3993.  *    menu, or as a toplevel (torn-off) menu or palette.
  3994.  *
  3995.  * Results:
  3996.  *    None.
  3997.  *
  3998.  * Side effects:
  3999.  *    Changes the style bit used to create a new Mac toplevel.
  4000.  *
  4001.  *----------------------------------------------------------------------
  4002.  */
  4003.  
  4004. void
  4005. TkMakeMenuWindow(tkwin, transient)
  4006.     Tk_Window tkwin;        /* New window. */
  4007.     int transient;        /* 1 means menu is only posted briefly as
  4008.                  * a popup or pulldown or cascade.  0 means
  4009.                  * menu is always visible, e.g. as a torn-off
  4010.                  * menu.  Determines whether save_under and
  4011.                  * override_redirect should be set. */
  4012. {
  4013.     XSetWindowAttributes atts;
  4014.  
  4015.     if (transient) {
  4016.     atts.override_redirect = True;
  4017.     atts.save_under = True;
  4018.     } else {
  4019.     atts.override_redirect = False;
  4020.     atts.save_under = False;
  4021.     }
  4022.     
  4023.     if ((atts.override_redirect != Tk_Attributes(tkwin)->override_redirect)
  4024.         || (atts.save_under != Tk_Attributes(tkwin)->save_under)) {
  4025.     Tk_ChangeWindowAttributes(tkwin,
  4026.         CWOverrideRedirect|CWSaveUnder, &atts);
  4027.     }
  4028.     
  4029. }
  4030.  
  4031. /*
  4032.  *----------------------------------------------------------------------
  4033.  *
  4034.  * TkWinGetWrapperWindow --
  4035.  *
  4036.  *    Gets the Windows HWND for a given window.
  4037.  *
  4038.  * Results:
  4039.  *    Returns the wrapper window for a Tk window.
  4040.  *
  4041.  * Side effects:
  4042.  *    None.
  4043.  *
  4044.  *----------------------------------------------------------------------
  4045.  */
  4046.  
  4047. HWND
  4048. TkWinGetWrapperWindow(
  4049.     Tk_Window tkwin)        /* The window we need the wrapper from */
  4050. {
  4051.     TkWindow *winPtr = (TkWindow *)tkwin;
  4052.     return (winPtr->wmInfoPtr->wrapper);
  4053. }
  4054.  
  4055.  
  4056. /*
  4057.  *----------------------------------------------------------------------
  4058.  *
  4059.  * TkWmFocusToplevel --
  4060.  *
  4061.  *    This is a utility procedure invoked by focus-management code. It
  4062.  *    exists because of the extra wrapper windows that exist under
  4063.  *    Unix; its job is to map from wrapper windows to the
  4064.  *    corresponding toplevel windows.  On PCs and Macs there are no
  4065.  *    wrapper windows so no mapping is necessary;  this procedure just
  4066.  *    determines whether a window is a toplevel or not.
  4067.  *
  4068.  * Results:
  4069.  *    If winPtr is a toplevel window, returns the pointer to the
  4070.  *    window; otherwise returns NULL.
  4071.  *
  4072.  * Side effects:
  4073.  *    None.
  4074.  *
  4075.  *----------------------------------------------------------------------
  4076.  */
  4077.  
  4078. TkWindow *
  4079. TkWmFocusToplevel(winPtr)
  4080.     TkWindow *winPtr;        /* Window that received a focus-related
  4081.                  * event. */
  4082. {
  4083.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  4084.     return NULL;
  4085.     }
  4086.     return winPtr;
  4087. }
  4088.  
  4089. /*
  4090.  *----------------------------------------------------------------------
  4091.  *
  4092.  * TkpGetWrapperWindow --
  4093.  *
  4094.  *    This is a utility procedure invoked by focus-management code. It
  4095.  *    maps to the wrapper for a top-level, which is just the same
  4096.  *    as the top-level on Macs and PCs.
  4097.  *
  4098.  * Results:
  4099.  *    If winPtr is a toplevel window, returns the pointer to the
  4100.  *    window; otherwise returns NULL.
  4101.  *
  4102.  * Side effects:
  4103.  *    None.
  4104.  *
  4105.  *----------------------------------------------------------------------
  4106.  */
  4107.  
  4108. TkWindow *
  4109. TkpGetWrapperWindow(
  4110.     TkWindow *winPtr)        /* Window that received a focus-related
  4111.                  * event. */
  4112. {
  4113.     if (!(winPtr->flags & TK_TOP_LEVEL)) {
  4114.     return NULL;
  4115.     }
  4116.     return winPtr;
  4117. }
  4118.